increased maximum difficulty multiplier to 30
[p2pool.git] / p2pool / bitcoin / script.py
1 from p2pool.util import math, pack
2
3 def reads_nothing(f):
4     return None, f
5 def protoPUSH(length):
6     return lambda f: pack.read(f, length)
7 def protoPUSHDATA(size_len):
8     def _(f):
9         length_str, f = pack.read(f, size_len)
10         length = math.string_to_natural(length_str[::-1].lstrip(chr(0)))
11         data, f = pack.read(f, length)
12         return data, f
13     return _
14
15 opcodes = {}
16 for i in xrange(256):
17     opcodes[i] = 'UNK_' + str(i), reads_nothing
18
19 opcodes[0] = 'PUSH', lambda f: ('', f)
20 for i in xrange(1, 76):
21     opcodes[i] = 'PUSH', protoPUSH(i)
22 opcodes[76] = 'PUSH', protoPUSHDATA(1)
23 opcodes[77] = 'PUSH', protoPUSHDATA(2)
24 opcodes[78] = 'PUSH', protoPUSHDATA(4)
25 opcodes[79] = 'PUSH', lambda f: ('\x81', f)
26 for i in xrange(81, 97):
27     opcodes[i] = 'PUSH', lambda f, _i=i: (chr(_i - 80), f)
28
29 opcodes[172] = 'CHECKSIG', reads_nothing
30 opcodes[173] = 'CHECKSIGVERIFY', reads_nothing
31 opcodes[174] = 'CHECKMULTISIG', reads_nothing
32 opcodes[175] = 'CHECKMULTISIGVERIFY', reads_nothing
33
34 def parse(script):
35     f = script, 0
36     while pack.size(f):
37         opcode_str, f = pack.read(f, 1)
38         opcode = ord(opcode_str)
39         opcode_name, read_func = opcodes[opcode]
40         opcode_arg, f = read_func(f)
41         yield opcode_name, opcode_arg
42
43 def get_sigop_count(script):
44     weights = {
45         'CHECKSIG': 1,
46         'CHECKSIGVERIFY': 1,
47         'CHECKMULTISIG': 20,
48         'CHECKMULTISIGVERIFY': 20,
49     }
50     return sum(weights.get(opcode_name, 0) for opcode_name, opcode_arg in parse(script))
51
52 def create_push_script(datums): # datums can be ints or strs
53     res = []
54     for datum in datums:
55         if isinstance(datum, (int, long)):
56             if datum == -1 or 1 <= datum <= 16:
57                 res.append(chr(datum + 80))
58                 continue
59             negative = datum < 0
60             datum = math.natural_to_string(abs(datum))
61             if datum and ord(datum[0]) & 128:
62                 datum = '\x00' + datum
63             if negative:
64                 datum = chr(ord(datum[0]) + 128) + datum[1:]
65             datum = datum[::-1]
66         if len(datum) < 76:
67             res.append(chr(len(datum)))
68         elif len(datum) <= 0xff:
69             res.append(76)
70             res.append(chr(len(datum)))
71         elif len(datum) <= 0xffff:
72             res.append(77)
73             res.append(pack.IntType(16).pack(len(datum)))
74         elif len(datum) <= 0xffffffff:
75             res.append(78)
76             res.append(pack.IntType(32).pack(len(datum)))
77         else:
78             raise ValueError('string too long')
79         res.append(datum)
80     return ''.join(res)