memory reductions
[p2pool.git] / p2pool / bitcoin / getwork.py
1 '''
2 Representation of a getwork request/reply
3 '''
4
5 from __future__ import division
6
7 from . import data as bitcoin_data
8 from . import sha256
9
10 def _swap(s, l):
11     return ''.join(s[x:x+l][::-1] for x in xrange(0, len(s), l))
12
13 class BlockAttempt(object):
14     def __init__(self, version, previous_block, merkle_root, timestamp, target, target2=None):
15         if target2 is None:
16             target2 = target
17         self.version, self.previous_block, self.merkle_root, self.timestamp, self.target, self.target2 = version, previous_block, merkle_root, timestamp, target, target2
18     
19     def __hash__(self):
20         return hash((self.version, self.previous_block, self.merkle_root, self.timestamp, self.target, self.target2))
21     
22     def __eq__(self, other):
23         if not isinstance(other, BlockAttempt):
24             raise ValueError('comparisons only valid with other BlockAttempts')
25         return self.__dict__ == other.__dict__
26     
27     def __ne__(self, other):
28         return not (self == other)
29     
30     def __repr__(self):
31         return 'BlockAttempt(%s)' % (', '.join('%s=%r' % (k, v) for k, v in self.__dict__.iteritems()),)
32     
33     def getwork(self, _check=3):
34         block_data = bitcoin_data.block_header_type.pack(dict(
35             version=self.version,
36             previous_block=self.previous_block,
37             merkle_root=self.merkle_root,
38             timestamp=self.timestamp,
39             target=self.target,
40             nonce=0,
41         ))
42         
43         getwork = {
44             'data': _swap(block_data, 4).encode('hex') + '000000800000000000000000000000000000000000000000000000000000000000000000000000000000000080020000',
45             'hash1': '00000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000010000',
46             'target': ('%064x' % (self.target2,)).decode('hex')[::-1].encode('hex'),
47             'midstate': _swap(sha256.process(block_data[:64]), 4).encode('hex'),
48         }
49         
50         if _check:
51             self2 = self.__class__.from_getwork(getwork, _check=_check - 1)
52             if self2 != self:
53                 raise ValueError('failed check - input invalid or implementation error')
54         
55         return getwork
56     
57     @classmethod
58     def from_getwork(cls, getwork, _check=3):
59         attrs = dict(decode_data(getwork['data']))
60         attrs.pop('nonce')
61         attrs['target2'] = int(getwork['target'].decode('hex')[::-1].encode('hex'), 16)
62         
63         ba = cls(**attrs)
64         
65         if _check:
66             getwork2 = ba.getwork(_check=_check - 1)
67             if getwork2 != getwork:
68                 raise ValueError('failed check - input invalid or implementation error')
69         
70         return ba
71     
72     def update(self, **kwargs):
73         d = self.__dict__.copy()
74         d.update(kwargs)
75         return self.__class__(**d)
76
77 def decode_data(data):
78     return bitcoin_data.block_header_type.unpack(_swap(data.decode('hex'), 4)[:80])
79
80 if __name__ == '__main__':
81     BlockAttempt.from_getwork({
82         'target': '0000000000000000000000000000000000000000000000f2b944000000000000',
83         'midstate': '5982f893102dec03e374b472647c4f19b1b6d21ae4b2ac624f3d2f41b9719404',
84         'hash1': '00000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000010000',
85         'data': '0000000163930d52a5ffca79b29b95a659a302cd4e1654194780499000002274000000002e133d9e51f45bc0886d05252038e421e82bff18b67dc14b90d9c3c2f422cd5c4dd4598e1a44b9f200000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000080020000'
86 }, _check=100)
87     BlockAttempt.from_getwork({
88         'midstate' : 'f4a9b048c0cb9791bc94b13ee0eec21e713963d524fd140b58bb754dd7b0955f',
89         'data' : '000000019a1d7342fb62090bda686b22d90f9f73d0f5c418b9c980cd0000011a00000000680b07c8a2f97ecd831f951806857e09f98a3b81cdef1fa71982934fef8dc3444e18585d1a0abbcf00000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000080020000',
90         'hash1' : '00000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000010000',
91         'target' : '0000000000000000000000000000000000000000000000cfbb0a000000000000'
92     })
93     ba = BlockAttempt(
94         1,
95         0x148135e10208db85abb62754341a392eab1f186aab077a831cf7,
96         0x534ea08be1ab529f484369344b6d5423ef5a0767db9b3ebb4e182bbb67962520,
97         1305759879,
98         0x44b9f20000000000000000000000000000000000000000000000,
99     )
100     ba.getwork(100)
101     ba = BlockAttempt(
102         1,
103         0x148135e10208db85abb62754341a392eab1f186aab077a831cf7,
104         0x534ea08be1ab529f484369344b6d5423ef5a0767db9b3ebb4e182bbb67962520,
105         1305759879,
106         0x44b9f20000000000000000000000000000000000000000000000,
107         432*2**230,
108     )
109     ba.getwork(100)
110     ba = BlockAttempt(
111         1,
112         0x148135e10208db85abb62754341a392eab1f186aab077a831cf7,
113         0x534ea08be1ab529f484369344b6d5423ef5a0767db9b3ebb4e182bbb67962520,
114         1305759879,
115         0x44b9f20000000000000000000000000000000000000000000000,
116         7*2**240,
117     )
118     ba.getwork(100)
119     ba.getwork()
120     ba.getwork(_check=100)
121     ba.update(previous_block=ba.previous_block - 10).getwork(_check=100)