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