1__author__ = 'bobalot'
2
3import struct
4import io
5import hashlib
6from binascii import hexlify, unhexlify
7from hashlib import sha256
8import models
9
10
11# Py3 compatibility
12import sys
13bchr = chr
14if sys.version > '3':
15    bchr = lambda x: bytes([x])
16
17
18def deser_uint32(f):
19    if type(f) is not io.BytesIO:
20        f = io.BytesIO(f)
21
22    return struct.unpack(b"<I", f.read(4))[0]
23
24
25def ser_uint32(u):
26    rs = b""
27    rs += struct.pack(b"<I", u & 0xFFFFFFFF)
28    return rs
29
30
31def deser_string(f):
32    nit = struct.unpack(b"<B", f.read(1))[0]
33    if nit == 253:
34        nit = struct.unpack(b"<H", f.read(2))[0]
35    elif nit == 254:
36        nit = struct.unpack(b"<I", f.read(4))[0]
37    elif nit == 255:
38        nit = struct.unpack(b"<Q", f.read(8))[0]
39    return f.read(nit)
40
41
42def ser_string(s):
43    if len(s) < 253:
44        return bchr(len(s)) + s
45    elif len(s) < 0x10000:
46        return bchr(253) + struct.pack(b"<H", len(s)) + s
47    elif len(s) < 0x100000000:
48        return bchr(254) + struct.pack(b"<I", len(s)) + s
49    return bchr(255) + struct.pack(b"<Q", len(s)) + s
50
51
52def deser_hash(f):
53    return f.read(32)
54
55
56def ser_hash(h):
57    return h[::-1]
58
59
60def deser_uint256(f):
61    r = 0
62    for i in range(8):
63        t = struct.unpack(b"<I", f.read(4))[0]
64        r += t << (i * 32)
65    return r
66
67
68def ser_uint256(u):
69    rs = b""
70    for i in range(8):
71        rs += struct.pack(b"<I", u & 0xFFFFFFFF)
72        u >>= 32
73    return rs
74
75
76def ser_uint160(u):
77    rs = b""
78    for i in range(5):
79        rs += struct.pack(b"<I", u & 0xFFFFFFFF)
80        u >>= 32
81    return rs
82
83
84def uint160_from_str(s):
85    r = 0
86    t = struct.unpack(b"<IIIII", s[:20])
87    for i in range(5):
88        r += t[i] << (i * 32)
89    return r
90
91
92def uint256_from_str(s):
93    r = 0
94    t = struct.unpack(b"<IIIIIIII", s[:32])
95    for i in range(8):
96        r += t[i] << (i * 32)
97    return r
98
99
100def uint256_from_compact(c):
101    nbytes = (c >> 24) & 0xFF
102    v = (c & 0xFFFFFF) << (8 * (nbytes - 3))
103    return v
104
105
106def uint256_to_shortstr(u):
107    s = "%064x" % (u,)
108    return s[:16]
109
110
111def deser_variable_uint(f):
112    length = struct.unpack(b"<B", f.read(1))[0]
113    if length < 0xfd:
114        return length
115    elif length == 0xfd:
116        return struct.unpack(b"<H", f.read(2))[0]
117    elif length == 0xfe:
118        return struct.unpack(b"<I", f.read(4))[0]
119    return struct.unpack(b"<Q", f.read(8))[0]
120
121
122def deser_vector(f, c, arg1=None):
123    count = deser_variable_uint(f)
124    r = []
125    for i in range(count):
126        #if arg1 is not None:
127        #    t = c(arg1)
128        #else:
129        #    t = c()
130
131        if c is models.TxIn:
132            t = deser_txin(f)
133        elif c is models.TxOut:
134            t = deser_txout(f)
135        elif c is models.Transaction:
136            t = deser_tx(f)
137        else:
138            raise NotImplementedError
139
140        r.append(t)
141    return r
142
143
144def ser_vector(l):
145    r = b""
146    if len(l) < 253:
147        r = bchr(len(l))
148    elif len(l) < 0x10000:
149        r = bchr(253) + struct.pack(b"<H", len(l))
150    elif len(l) < 0x100000000:
151        r = bchr(254) + struct.pack(b"<I", len(l))
152    else:
153        r = bchr(255) + struct.pack(b"<Q", len(l))
154
155    for i in l:
156        if type(i) is models.TxIn:
157            r += ser_txin(i)
158        elif type(i) is models.TxOut:
159            r += ser_txout(i)
160        elif type(i) is models.Transaction:
161            r += ser_tx(i)
162        else:
163            raise NotImplementedError
164
165    return r
166
167
168def deser_uint256_vector(f):
169    nit = struct.unpack(b"<B", f.read(1))[0]
170    if nit == 253:
171        nit = struct.unpack(b"<H", f.read(2))[0]
172    elif nit == 254:
173        nit = struct.unpack(b"<I", f.read(4))[0]
174    elif nit == 255:
175        nit = struct.unpack(b"<Q", f.read(8))[0]
176    r = []
177    for i in range(nit):
178        t = deser_uint256(f)
179        r.append(t)
180    return r
181
182
183def ser_uint256_vector(l):
184    r = b""
185    if len(l) < 253:
186        r = bchr(len(l))
187    elif len(l) < 0x10000:
188        r = bchr(253) + struct.pack(b"<H", len(l))
189    elif len(l) < 0x100000000:
190        r = bchr(254) + struct.pack(b"<I", len(l))
191    else:
192        r = bchr(255) + struct.pack(b"<Q", len(l))
193    for i in l:
194        r += ser_uint256(i)
195    return r
196
197
198def deser_string_vector(f):
199    nit = struct.unpack(b"<B", f.read(1))[0]
200    if nit == 253:
201        nit = struct.unpack(b"<H", f.read(2))[0]
202    elif nit == 254:
203        nit = struct.unpack(b"<I", f.read(4))[0]
204    elif nit == 255:
205        nit = struct.unpack(b"<Q", f.read(8))[0]
206    r = []
207    for i in range(nit):
208        t = deser_string(f)
209        r.append(t)
210    return r
211
212
213def ser_string_vector(l):
214    r = b""
215    if len(l) < 253:
216        r = bchr(len(l))
217    elif len(l) < 0x10000:
218        r = bchr(253) + struct.pack(b"<H", len(l))
219    elif len(l) < 0x100000000:
220        r = bchr(254) + struct.pack(b"<I", len(l))
221    else:
222        r = bchr(255) + struct.pack(b"<Q", len(l))
223    for sv in l:
224        r += ser_string(sv)
225    return r
226
227
228def deser_int_vector(f):
229    nit = struct.unpack(b"<B", f.read(1))[0]
230    if nit == 253:
231        nit = struct.unpack(b"<H", f.read(2))[0]
232    elif nit == 254:
233        nit = struct.unpack(b"<I", f.read(4))[0]
234    elif nit == 255:
235        nit = struct.unpack(b"<Q", f.read(8))[0]
236    r = []
237    for i in range(nit):
238        t = struct.unpack(b"<i", f.read(4))[0]
239        r.append(t)
240    return r
241
242
243def ser_int_vector(l):
244    r = b""
245    if len(l) < 253:
246        r = bchr(len(l))
247    elif len(l) < 0x10000:
248        r = bchr(253) + struct.pack(b"<H", len(l))
249    elif len(l) < 0x100000000:
250        r = bchr(254) + struct.pack(b"<I", len(l))
251    else:
252        r = bchr(255) + struct.pack(b"<Q", len(l))
253    for i in l:
254        r += struct.pack(b"<i", i)
255    return r
256
257
258def Hash(s):
259    return uint256_from_str(
260        hashlib.sha256(hashlib.sha256(s).digest()).digest()
261    )
262
263
264def Hash160(s):
265    h = hashlib.new('ripemd160')
266    h.update(hashlib.sha256(s).digest())
267    return uint160_from_str(h.digest())
268
269
270def ser_destination(destination):
271    if destination is None:
272        serialized = ""
273    else:
274        try:
275            serialized = unhexlify(destination)
276        except TypeError:
277            serialized = destination
278
279    return serialized
280
281
282def deser_txout(f):
283    txout = models.TxOut()
284    txout.value = struct.unpack(b"<q", f.read(8))[0]
285    txout.script = deser_string(f)
286    return txout
287
288
289def ser_txout(txout):
290    r = b""
291    r += struct.pack(b"<q", txout.value)
292    r += ser_string(txout.script)
293    return r
294
295
296def deser_output_point(f):
297    if type(f) is not io.BytesIO:
298        f = io.BytesIO(f)
299
300    outpoint = models.OutPoint()
301    outpoint.hash = deser_hash(f)[::-1]
302    outpoint.index = deser_uint32(f.read(4))
303    return outpoint
304
305
306def ser_output_point(outpoint):
307    r = b""
308    r += ser_hash(outpoint.hash)
309    r += ser_uint32(outpoint.index)
310    return r
311
312
313def deser_txin(f):
314    if type(f) is not io.BytesIO:
315        f = io.BytesIO(f)
316
317    txin = models.TxIn()
318    txin.previous_output = deser_output_point(f)
319    txin.script = deser_string(f)
320    txin.sequence = deser_uint32(f)
321    return txin
322
323
324def ser_txin(txin):
325    r = b""
326    r += ser_output_point(txin.previous_output)
327    r += ser_string(txin.script)
328    r += ser_uint32(txin.sequence)
329    return r
330
331
332def deser_block_header(f):
333    if type(f) is not io.BytesIO:
334        f = io.BytesIO(f)
335
336    h = models.BlockHeader()
337
338    h.version = deser_uint32(f.read(4))
339    h.previous_block_hash = f.read(32)
340    h.merkle = f.read(32)
341    h.timestamp = deser_uint32(f.read(4))
342    h.bits = deser_uint32(f.read(4))
343    h.nonce = deser_uint32(f.read(4))
344
345    return h
346
347
348def ser_block_header(block_header):
349    output = b""
350    output += ser_uint32(block_header.version)
351    output += block_header.previous_block_hash
352    output += block_header.merkle
353    output += ser_uint32(block_header.timestamp)
354    output += ser_uint32(block_header.bits)
355    output += ser_uint32(block_header.nonce)
356
357    return output
358
359
360def deser_tx(f):
361    if type(f) is not io.BytesIO:
362        f = io.BytesIO(f)
363
364    tx = models.Transaction()
365    tx.version = deser_uint32(f.read(4))
366    tx.inputs = deser_vector(f, models.TxIn)
367    tx.outputs = deser_vector(f, models.TxOut)
368    tx.locktime = deser_uint32(f)
369    return tx
370
371
372def ser_tx(tx):
373    r = b""
374    r += ser_uint32(tx.version)
375    r += ser_vector(tx.inputs)
376    r += ser_vector(tx.outputs)
377    r += ser_uint32(tx.locktime)
378    return r
379
380
381def deser_block(f):
382    if type(f) is not io.BytesIO:
383        f = io.BytesIO(f)
384
385    blk = models.Block()
386
387    blk.header = deser_block_header(f)
388    blk.transactions = deser_vector(f, models.Transaction)
389    return blk
390
391
392def ser_block(blk):
393    r = b""
394    r += ser_block_header(blk.header)
395    r += ser_vector(blk.transaction_list, models.Transaction)
396
397    return r
398
399    #tx.version = struct.unpack(b"<i", f.read(4))[0]
400    #tx.vin = deser_vector(f, TxIn)
401    #tx.vout = deser_vector(f, TxOut)
402    #tx.nLockTime = struct.unpack(b"<I", f.read(4))[0]
403
404
405def deser_history_row(f):
406    if type(f) is not io.BytesIO:
407        f = io.BytesIO(f)
408
409    hr = models.history_row()
410
411    hr.output_hash = f.read(32)
412    hr.output_index = deser_uint32(f)
413    hr.output_height = deser_uint32(f)
414
415    hr.value = struct.unpack(b"<q", f.read(8))[0]
416    hr.spend_hash = f.read(32)
417    hr.spend_index = deser_uint32(f)
418    hr.spend_height = deser_uint32(f)
419
420    return hr
421
422
423def ser_history_row(hr):
424    r = b""
425
426    r += hr.output_hash
427    r += ser_uint32(hr.output_index)
428    r += ser_uint32(hr.output_height)
429
430    r += struct.pack(b"<q", hr.value & 0xFFFFFFFFFFFFFFFF)
431    r += hr.spend_hash
432    r += ser_uint32(hr.spend_index)
433    r += ser_uint32(hr.spend_height)
434
435    return hr
436
437
438def deser_history_row_list(bytes):
439    row_bytes = 88
440    num_rows = len(bytes) / row_bytes
441
442    assert(len(bytes) % row_bytes == 0)
443
444    history_list = []
445
446    for i in range(num_rows):
447        begin = i * row_bytes
448        end = begin + row_bytes
449        history_list.append(deser_history_row(bytes[begin, end]))
450
451    return history_list
452
453
454def dsha256(data):
455    return sha256(sha256(data).digest()).digest()[::-1]
456
457
458def checksum(data):
459    return sha256(sha256(data).digest()).digest()[:4]
460
461
462def hash_block_header(blk_head):
463    if type(blk_head) is models.Block:
464        blk_head = blk_head.header
465
466    serial = ser_block_header(blk_head)
467
468    return dsha256(serial)
469
470
471def hash_transaction(tx):
472    if type(tx) is not models.Transaction:
473        return False
474
475    serial = ser_tx(tx)
476
477    return dsha256(serial)
478
479
480def ser_data(command, data):
481    # This requires command at the moment, for no reason.
482    # Fix this.
483    #from models import commands
484    #if command not in commands:
485    #    raise NotImplementedError
486
487    if type(data) is int:
488        return ser_uint32(data)
489    elif type(data) is str:
490        return data
491
492    elif type(data) is tuple:
493        r = b""
494
495        for element in data:
496
497            r += ser_data(command, element)
498
499        return r
500
501
502def deser_address_update(f):
503    if type(f) is not io.BytesIO:
504        f = io.BytesIO(f)
505
506    update = models.address_update()
507    update.address_version_byte = f.read(1)
508    update.address_hash = f.read(20)
509
510    update.height = deser_uint32(f)
511    update.tx = deser_tx(f)
512
513    return update
514
515
516#command_data_type = \
517#        {"blockchain.fetch_transaction",
518#            "blockchain.fetch_last_height",
519#            "blockchain.fetch_block_header",
520#            "blockchain.fetch_block_transaction_hashes",
521#            "transaction_pool.validate",
522#            "protocol.broadcast_transaction",
523#            "address.fetch_history"]
524
525
526# deserialize and remove the ec here,
527# this leaves all the other functions able to
528# do deserialization on normal bitcoin serials.
529def deser_data(command, data_bytes):
530    if command == "blockchain.fetch_transaction":
531        return data_bytes[:4], deser_tx(data_bytes[4:])
532
533    elif command == "blockchain.fetch_last_height":
534        return data_bytes[:4], deser_uint32(data_bytes[4:])
535
536    elif command == "blockchain.fetch_block_header":
537        return data_bytes[:4], deser_block_header(data_bytes[4:])
538
539    elif command == "blockchain.fetch_block_transaction_hashes":
540        hash_list = []
541
542        print hexlify(data_bytes[4:])
543
544        assert((len(data_bytes)-4) % 32 == 0)
545
546        f = io.BytesIO(data_bytes)
547        ec = f.read(4)
548
549        for i in range(data_bytes/32):
550            hash_list.append(f.read(32))
551
552        return ec, hash_list
553
554    elif command == "address.fetch_history":
555        # history row is 88 bytes long. Assert there is nothing else
556        assert((len(data_bytes)-4) % 88 == 0)
557
558        history_list = []
559
560        # use bytesio, as this will probably be a long message
561        f = io.BytesIO(data_bytes)
562        ec = f.read(4)
563
564        for i in range(len(data_bytes) / 88):
565            history_list.append(deser_history_row(f))
566
567        return ec, history_list
568
569    elif command == "address.subscribe":
570        if len(data_bytes) == 4:
571            ec = deser_uint32(data_bytes)
572
573        return ec, None
574
575    elif command == "address.update":
576        # No error code in address.update
577        f = io.BytesIO(data_bytes)
578
579        ec = 0
580        return ec, deser_address_update(f)
581