Typo fix
[stratum-mining.git] / lib / util.py
1 '''Various helper methods. It probably needs some cleanup.'''
2
3 import struct
4 import StringIO
5 import binascii
6 from hashlib import sha256
7 from ltc_scrypt import getPoWHash
8
9 def deser_string(f):
10     nit = struct.unpack("<B", f.read(1))[0]
11     if nit == 253:
12         nit = struct.unpack("<H", f.read(2))[0]
13     elif nit == 254:
14         nit = struct.unpack("<I", f.read(4))[0]
15     elif nit == 255:
16         nit = struct.unpack("<Q", f.read(8))[0]
17     return f.read(nit)
18
19 def ser_string(s):
20     if len(s) < 253:
21         return chr(len(s)) + s
22     elif len(s) < 0x10000:
23         return chr(253) + struct.pack("<H", len(s)) + s
24     elif len(s) < 0x100000000L:
25         return chr(254) + struct.pack("<I", len(s)) + s
26     return chr(255) + struct.pack("<Q", len(s)) + s
27
28 def deser_uint256(f):
29     r = 0L
30     for i in xrange(8):
31         t = struct.unpack("<I", f.read(4))[0]
32         r += t << (i * 32)
33     return r
34
35 def ser_uint256(u):
36     rs = ""
37     for i in xrange(8):
38         rs += struct.pack("<I", u & 0xFFFFFFFFL)
39         u >>= 32
40     return rs
41
42 def uint256_from_str(s):
43     r = 0L
44     t = struct.unpack("<IIIIIIII", s[:32])
45     for i in xrange(8):
46         r += t[i] << (i * 32)
47     return r
48
49 def uint256_from_str_be(s):
50     r = 0L
51     t = struct.unpack(">IIIIIIII", s[:32])
52     for i in xrange(8):
53         r += t[i] << (i * 32)
54     return r
55
56 def uint256_from_compact(c):
57     nbytes = (c >> 24) & 0xFF
58     v = (c & 0xFFFFFFL) << (8 * (nbytes - 3))
59     return v
60
61 def deser_vector(f, c):
62     nit = struct.unpack("<B", f.read(1))[0]
63     if nit == 253:
64         nit = struct.unpack("<H", f.read(2))[0]
65     elif nit == 254:
66         nit = struct.unpack("<I", f.read(4))[0]
67     elif nit == 255:
68         nit = struct.unpack("<Q", f.read(8))[0]
69     r = []
70     for i in xrange(nit):
71         t = c()
72         t.deserialize(f)
73         r.append(t)
74     return r
75
76 def ser_vector(l):
77     r = ""
78     if len(l) < 253:
79         r = chr(len(l))
80     elif len(l) < 0x10000:
81         r = chr(253) + struct.pack("<H", len(l))
82     elif len(l) < 0x100000000L:
83         r = chr(254) + struct.pack("<I", len(l))
84     else:
85         r = chr(255) + struct.pack("<Q", len(l))
86     for i in l:
87         r += i.serialize()
88     return r
89
90 def deser_uint256_vector(f):
91     nit = struct.unpack("<B", f.read(1))[0]
92     if nit == 253:
93         nit = struct.unpack("<H", f.read(2))[0]
94     elif nit == 254:
95         nit = struct.unpack("<I", f.read(4))[0]
96     elif nit == 255:
97         nit = struct.unpack("<Q", f.read(8))[0]
98     r = []
99     for i in xrange(nit):
100         t = deser_uint256(f)
101         r.append(t)
102     return r
103
104 def ser_uint256_vector(l):
105     r = ""
106     if len(l) < 253:
107         r = chr(len(l))
108     elif len(l) < 0x10000:
109         r = chr(253) + struct.pack("<H", len(l))
110     elif len(l) < 0x100000000L:
111         r = chr(254) + struct.pack("<I", len(l))
112     else:
113         r = chr(255) + struct.pack("<Q", len(l))
114     for i in l:
115         r += ser_uint256(i)
116     return r
117
118 __b58chars = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
119 __b58base = len(__b58chars)
120
121 def b58decode(v, length):
122     """ decode v into a string of len bytes
123     """
124     long_value = 0L
125     for (i, c) in enumerate(v[::-1]):
126         long_value += __b58chars.find(c) * (__b58base**i)
127
128     result = ''
129     while long_value >= 256:
130         div, mod = divmod(long_value, 256)
131         result = chr(mod) + result
132         long_value = div
133     result = chr(long_value) + result
134
135     nPad = 0
136     for c in v:
137         if c == __b58chars[0]: nPad += 1
138         else: break
139
140     result = chr(0)*nPad + result
141     if length is not None and len(result) != length:
142         return None
143
144     return result
145
146 def b58encode(value):
147     """ encode integer 'value' as a base58 string; returns string
148     """
149     encoded = ''
150     while value >= __b58base:
151         div, mod = divmod(value, __b58base)
152         encoded = __b58chars[mod] + encoded # add to left
153         value = div
154     encoded = __b58chars[value] + encoded # most significant remainder
155     return encoded
156
157 def reverse_hash(h):
158     # This only revert byte order, nothing more
159     if len(h) != 64:
160         raise Exception('hash must have 64 hexa chars')
161
162     return ''.join([ h[56-i:64-i] for i in range(0, 64, 8) ])
163
164 def doublesha(b):
165     return sha256(sha256(b).digest()).digest()
166
167 def scrypt(b):
168     return getPoWHash(b)
169
170 def bits_to_target(bits):
171     return struct.unpack('<L', bits[:3] + b'\0')[0] * 2**(8*(int(bits[3], 16) - 3))
172
173 def address_to_pubkeyhash(addr):
174     try:
175         addr = b58decode(addr, 25)
176     except:
177         return None
178
179     if addr is None:
180         return None
181
182     ver = addr[0]
183     cksumA = addr[-4:]
184     cksumB = doublesha(addr[:-4])[:4]
185
186     if cksumA != cksumB:
187         return None
188
189     return (ver, addr[1:-4])
190
191 def ser_uint256_be(u):
192     '''ser_uint256 to big endian'''
193     rs = ""
194     for i in xrange(8):
195         rs += struct.pack(">I", u & 0xFFFFFFFFL)
196         u >>= 32
197     return rs
198
199 def deser_uint256_be(f):
200     r = 0L
201     for i in xrange(8):
202         t = struct.unpack(">I", f.read(4))[0]
203         r += t << (i * 32)
204     return r
205
206 def ser_number(n):
207     # For encoding nHeight into coinbase
208     s = bytearray(b'\1')
209     while n > 127:
210         s[0] += 1
211         s.append(n % 256)
212         n //= 256
213     s.append(n)
214     return bytes(s)
215
216 def script_to_address(addr):
217     d = address_to_pubkeyhash(addr)
218     if not d:
219         raise ValueError('invalid address')
220     (ver, pubkeyhash) = d
221     return b'\x76\xa9\x14' + pubkeyhash + b'\x88\xac'