1from . import errno
2
3from .flags import (
4    SEQUENCE_LOCKTIME_DISABLE_FLAG, SEQUENCE_LOCKTIME_TYPE_FLAG,
5    VERIFY_DISCOURAGE_UPGRADABLE_NOPS,
6    VERIFY_CHECKLOCKTIMEVERIFY,
7    VERIFY_MINIMALIF, VERIFY_CHECKSEQUENCEVERIFY,
8)
9
10from pycoin.coins.SolutionChecker import ScriptError
11
12
13def make_bad_opcode(opcode, even_outside_conditional=False, err=errno.BAD_OPCODE):
14    def bad_opcode(vm):
15        raise ScriptError("invalid opcode %s at %d" % (opcode, vm.pc-1), err)
16    bad_opcode.outside_conditional = even_outside_conditional
17    return bad_opcode
18
19
20def do_OP_CODESEPARATOR(vm):
21    vm.begin_code_hash = vm.pc
22
23
24def do_OP_TOALTSTACK(vm):
25    vm.altstack.append(vm.pop())
26
27
28def do_OP_RESERVED(vm):
29    if vm.conditional_stack.all_if_true():
30        raise ScriptError("OP_RESERVED encountered", errno.BAD_OPCODE)
31    vm.op_count -= 1
32
33
34do_OP_RESERVED.outside_conditional = True
35
36
37def do_OP_FROMALTSTACK(vm):
38    if len(vm.altstack) < 1:
39        raise ScriptError("alt stack empty", errno.INVALID_ALTSTACK_OPERATION)
40    vm.append(vm.altstack.pop())
41
42
43def discourage_nops(vm):
44    if (vm.flags & VERIFY_DISCOURAGE_UPGRADABLE_NOPS):
45        raise ScriptError("discouraging nops", errno.DISCOURAGE_UPGRADABLE_NOPS)
46
47
48def make_if(reverse_bool=False):
49    def f(vm):
50        stack = vm.stack
51        conditional_stack = vm.conditional_stack
52        the_bool = False
53        if conditional_stack.all_if_true():
54            if len(stack) < 1:
55                raise ScriptError("IF with no condition", errno.UNBALANCED_CONDITIONAL)
56            item = vm.pop()
57            if vm.flags & VERIFY_MINIMALIF:
58                if item not in (vm.VM_FALSE, vm.VM_TRUE):
59                    raise ScriptError("non-minimal IF", errno.MINIMALIF)
60            the_bool = vm.bool_from_script_bytes(item)
61        vm.conditional_stack.OP_IF(the_bool, reverse_bool=reverse_bool)
62    f.outside_conditional = True
63    return f
64
65
66def do_OP_ELSE(vm):
67    vm.conditional_stack.OP_ELSE()
68
69
70do_OP_ELSE.outside_conditional = True
71
72
73def do_OP_ENDIF(vm):
74    vm.conditional_stack.OP_ENDIF()
75
76
77do_OP_ENDIF.outside_conditional = True
78
79
80def do_OP_CHECKLOCKTIMEVERIFY(vm):
81    if not (vm.flags & VERIFY_CHECKLOCKTIMEVERIFY):
82        if (vm.flags & VERIFY_DISCOURAGE_UPGRADABLE_NOPS):
83            raise ScriptError("discouraging nops", errno.DISCOURAGE_UPGRADABLE_NOPS)
84        return
85    if vm.tx_context.sequence == 0xffffffff:
86        raise ScriptError("nSequence equal to 0xffffffff")
87    if len(vm.stack) < 1:
88        raise ScriptError("empty stack on CHECKLOCKTIMEVERIFY")
89    if len(vm.stack[-1]) > 5:
90        raise ScriptError("script number overflow")
91    max_lock_time = vm.pop_int()
92    vm.push_int(max_lock_time)
93    if max_lock_time < 0:
94        raise ScriptError("top stack item negative on CHECKLOCKTIMEVERIFY")
95    era_max = (max_lock_time >= 500000000)
96    era_lock_time = (vm.tx_context.lock_time >= 500000000)
97    if era_max != era_lock_time:
98        raise ScriptError("eras differ in CHECKLOCKTIMEVERIFY")
99    if max_lock_time > vm.tx_context.lock_time:
100        raise ScriptError("nLockTime too soon")
101
102
103def _check_sequence_verify(sequence, tx_context_sequence):
104    # this mask is applied to extract lock-time from the sequence field
105    SEQUENCE_LOCKTIME_MASK = 0xffff
106
107    mask = SEQUENCE_LOCKTIME_TYPE_FLAG | SEQUENCE_LOCKTIME_MASK
108    sequence_masked = sequence & mask
109    tx_sequence_masked = tx_context_sequence & mask
110    if not (((tx_sequence_masked < SEQUENCE_LOCKTIME_TYPE_FLAG) and
111             (sequence_masked < SEQUENCE_LOCKTIME_TYPE_FLAG)) or
112            ((tx_sequence_masked >= SEQUENCE_LOCKTIME_TYPE_FLAG) and
113             (sequence_masked >= SEQUENCE_LOCKTIME_TYPE_FLAG))):
114        raise ScriptError("sequence numbers not comparable")
115    if sequence_masked > tx_sequence_masked:
116        raise ScriptError("sequence number too small")
117
118
119def do_OP_CHECKSEQUENCEVERIFY(vm):
120    if not (vm.flags & VERIFY_CHECKSEQUENCEVERIFY):
121        if (vm.flags & VERIFY_DISCOURAGE_UPGRADABLE_NOPS):
122            raise ScriptError("discouraging nops", errno.DISCOURAGE_UPGRADABLE_NOPS)
123        return
124    if len(vm.stack) < 1:
125        raise ScriptError("empty stack on CHECKSEQUENCEVERIFY", errno.INVALID_STACK_OPERATION)
126    if len(vm.stack[-1]) > 5:
127        raise ScriptError("script number overflow", errno.INVALID_STACK_OPERATION+1)
128    sequence = vm.pop_int()
129    vm.push_int(sequence)
130    if sequence < 0:
131        raise ScriptError(
132            "top stack item negative on CHECKSEQUENCEVERIFY", errno.NEGATIVE_LOCKTIME)
133    if sequence & SEQUENCE_LOCKTIME_DISABLE_FLAG:
134        return
135    # do the actual check
136    if vm.tx_context.version < 2:
137        raise ScriptError("CHECKSEQUENCEVERIFY: bad tx version", errno.UNSATISFIED_LOCKTIME)
138    if vm.tx_context.sequence & SEQUENCE_LOCKTIME_DISABLE_FLAG:
139        raise ScriptError("CHECKSEQUENCEVERIFY: locktime disabled")
140
141    _check_sequence_verify(sequence, vm.tx_context.sequence)
142
143
144def extra_opcodes():
145    d = {}
146    BAD_OPCODES = "OP_VERIF OP_VERNOTIF ".split()
147    for opcode in BAD_OPCODES:
148        d[opcode] = make_bad_opcode(opcode, even_outside_conditional=True)
149
150    DISABLED_OPCODES = (
151        "OP_CAT OP_SUBSTR OP_LEFT OP_RIGHT OP_INVERT OP_AND OP_OR OP_XOR OP_2MUL OP_2DIV OP_MUL "
152        "OP_DIV OP_MOD OP_LSHIFT OP_RSHIFT".split())
153    for opcode in DISABLED_OPCODES:
154        d[opcode] = make_bad_opcode(
155            opcode, even_outside_conditional=True, err=errno.DISABLED_OPCODE)
156
157    BAD_OPCODES_OUTSIDE_IF = "OP_NULLDATA OP_PUBKEYHASH OP_PUBKEY OP_INVALIDOPCODE".split()
158    for opcode in BAD_OPCODES_OUTSIDE_IF:
159        d[opcode] = make_bad_opcode(opcode, even_outside_conditional=False)
160
161    NOP_SET = (
162        "OP_NOP1 OP_NOP3 OP_NOP4 OP_NOP5 OP_NOP6 OP_NOP7 OP_NOP8 OP_NOP9 OP_NOP10".split())
163    for opcode in NOP_SET:
164        d[opcode] = discourage_nops
165
166    d["OP_IF"] = make_if()
167    d["OP_NOTIF"] = make_if(reverse_bool=True)
168
169    for i in (1, 2, 4):
170        d["OP_PUSHDATA%d" % i] = lambda s: 0
171
172    for v in range(0, 128):
173        d["OP_%d" % v] = lambda s: 0
174    return d
175
176
177"""
178The MIT License (MIT)
179
180Copyright (c) 2013-2017 by Richard Kiss
181
182Permission is hereby granted, free of charge, to any person obtaining a copy
183of this software and associated documentation files (the "Software"), to deal
184in the Software without restriction, including without limitation the rights
185to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
186copies of the Software, and to permit persons to whom the Software is
187furnished to do so, subject to the following conditions:
188
189The above copyright notice and this permission notice shall be included in
190all copies or substantial portions of the Software.
191
192THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
193IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
194FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
195AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
196LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
197OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
198THE SOFTWARE.
199"""
200