d0bc1d8474bf101d4f57ac32b89f3ad9aeb48af8
[p2pool.git] / conv.py
1 '''
2 Representation of a getwork request/reply
3 '''
4
5 from __future__ import division
6
7 import struct
8
9 import sha256
10
11 def bits_to_target(bits):
12     return (bits & 0x00ffffff) * 2 ** (8 * ((bits >> 24) - 3))
13
14 def target_to_attempts(target):
15     return (2**257 + target + 1)//(2*target + 2)
16
17 def reverse_chunks(s, l):
18     return ''.join(reversed([s[x:x+l] for x in xrange(0, len(s), l)]))
19
20 class BlockAttempt(object):
21     def __init__(self, version, previous_block, merkle_root, timestamp, bits):
22         self.version, self.previous_block, self.merkle_root, self.timestamp, self.bits = version, previous_block, merkle_root, timestamp, bits
23     
24     def __repr__(self):
25         return '<BlockAttempt %s>' % (' '.join('%s=%s' % (k, hex(v))) for k, v in self.__dict__.iteritems())
26     
27     def __eq__(self, other):
28         if not isinstance(other, BlockAttempt):
29             raise ValueError('comparisons only valid with other BlockAttempts')
30         return self.__dict__ == other.__dict__
31     
32     def __ne__(self, other):
33         return not (self == other)
34     
35     def __repr__(self):
36         return 'BlockAttempt(%s)' % (', '.join('%s=%r' % (k, v) for k, v in self.__dict__.iteritems()),)
37     
38     def getwork(self, target_multiplier=1, _check=2):
39         target = bits_to_target(self.bits) * target_multiplier
40         if target >= 2**256//2**32:
41             raise ValueError("target higher than standard maximum")
42         
43         previous_block2 = reverse_chunks('%064x' % self.previous_block, 8).decode('hex')
44         merkle_root2 = reverse_chunks('%064x' % self.merkle_root, 8).decode('hex')
45         data = struct.pack('>I32s32sIII', self.version, previous_block2, merkle_root2, self.timestamp, self.bits, 0).encode('hex') + '000000800000000000000000000000000000000000000000000000000000000000000000000000000000000080020000'
46         
47         previous_block3 = ('%064x' % self.previous_block).decode('hex')[::-1]
48         merkle_root3 = ('%064x' % self.merkle_root).decode('hex')[::-1]
49         data2 = struct.pack('<I32s32s', self.version, previous_block3, merkle_root3)
50         
51         getwork = {
52             'data': data,
53             'hash1': '00000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000010000',
54             'target': ('%064x' % (target,)).decode('hex')[::-1].encode('hex'),
55             'midstate': reverse_chunks(sha256.process(data2[:64])[::-1], 4).encode('hex'),
56         }
57         
58         if _check:
59             self2 = self.__class__.from_getwork(getwork, _check=_check - 1, _check_multiplier=target_multiplier)
60             if self2 != self:
61                 raise ValueError('failed check - input invalid or implementation error')
62         
63         return getwork
64     
65     @classmethod
66     def from_getwork(cls, getwork, _check=2, _check_multiplier=1):
67         attrs = decode_data(getwork['data'])
68         attrs.pop('nonce')
69         
70         ba = cls(**attrs)
71         
72         if _check:
73             getwork2 = ba.getwork(_check_multiplier, _check=_check - 1)
74             if getwork2 != getwork:
75                 raise ValueError('failed check - input invalid or implementation error')
76         
77         return ba
78
79 def decode_data(data):
80     version, previous_block, merkle_root, timestamp, bits, nonce = struct.unpack('>I32s32sIII', data[:160].decode('hex'))
81     previous_block = int(reverse_chunks(previous_block.encode('hex'), 8), 16)
82     merkle_root = int(reverse_chunks(merkle_root.encode('hex'), 8), 16)
83     return dict(version=version, previous_block=previous_block, merkle_root=merkle_root, timestamp=timestamp, bits=bits, nonce=nonce)
84
85 if __name__ == '__main__':
86     ba = BlockAttempt(
87         1,
88         0x000000000000148135e10208db85abb62754341a392eab1f186aab077a831cf7,
89         0x534ea08be1ab529f484369344b6d5423ef5a0767db9b3ebb4e182bbb67962520,
90         1305759879,
91         440711666,
92     )
93     ba.getwork(1, 100)
94     ba.getwork(10, 100)
95     ba.from_getwork({
96         'target': '0000000000000000000000000000000000000000000000f2b944000000000000',
97         'midstate': '5982f893102dec03e374b472647c4f19b1b6d21ae4b2ac624f3d2f41b9719404',
98         'hash1': '00000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000010000',
99         'data': '0000000163930d52a5ffca79b29b95a659a302cd4e1654194780499000002274000000002e133d9e51f45bc0886d05252038e421e82bff18b67dc14b90d9c3c2f422cd5c4dd4598e1a44b9f200000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000080020000'
100 }, _check=100)