Ejemplo n.º 1
0
 def get_human(self):
     """Get the script as a human-readable string."""
     s = []
     iterator = self.raw_iter()
     while 1:
         try:
             opcode, data, byte_index = next(iterator)
             op_name = OPCODE_NAMES.get(opcode)
             if op_name:
                 s.append(op_name)
             elif opcode < OPCODES_BY_NAME["OP_PUSHDATA1"]:
                 s.append("".join(["0x", data.encode("hex")]))
         except StopIteration:
             break
         except Exception:
             s.append("(CANNOT_PARSE)")
     return " ".join(s)
Ejemplo n.º 2
0
 def get_human(self):
     """Get the script as a human-readable string."""
     s = []
     iterator = self.raw_iter()
     while 1:
         try:
             opcode, data, byte_index = next(iterator)
             op_name = OPCODE_NAMES.get(opcode)
             if op_name:
                 s.append(op_name)
             elif opcode < OPCODES_BY_NAME['OP_PUSHDATA1']:
                 s.append(''.join(['0x', data.encode('hex')]))
         except StopIteration:
             break
         except Exception:
             s.append('(CANNOT_PARSE)')
     return ' '.join(s)
Ejemplo n.º 3
0
    def do_step(self):
        """Returns whether another step can be done."""
        if self.step_counter == -1:
            txt = str(self.tx_script.toPlainText())
            scr = CScript(txt.decode('hex'))
            # So we can show the opcode in the stack log
            self.script_ops = [i for i in scr.raw_iter()]
            self.stack.set_script(scr, self.tx, self.inIdx)
            self.stack_iterator = self.stack.step()
            self.stack_log.clear()
            self.step_counter += 1

        step_again = False
        try:
            self.step_counter += 1
            stack_state, action = self.stack_iterator.next()
            new_stack = [i.encode('hex') for i in reversed(stack_state)]
            self.stack_view.clear()
            self.stack_view.addItems(new_stack)

            op_name = OPCODE_NAMES.get(
                self.script_ops[self.step_counter - 1][0], 'PUSHDATA')
            self.highlight_step(self.script_ops[self.step_counter - 1])
            item = QTreeWidgetItem(
                map(lambda i: str(i), [self.step_counter, op_name, action]))
            item.setTextAlignment(0, Qt.AlignLeft)
            item.setToolTip(1, 'Step {} operation'.format(self.step_counter))
            item.setToolTip(2, 'Result of step {}'.format(self.step_counter))
            self.stack_log.insertTopLevelItem(0, item)
            self.stack_result.setText(action)
            self.stack_result.setProperty('hasError', False)
            step_again = True
        except StopIteration:
            self.stack_result.setText('End of script.')
        except Exception as e:
            self.stack_result.setText(str(e))
            self.stack_result.setProperty('hasError', True)
        finally:
            self.style().polish(self.stack_result)

        return step_again
Ejemplo n.º 4
0
def transform_human(text, variables=None):
    """Transform user input with given context.

    Args:
        text (str): User input.
        variables (dict): Variables for purposes of substitution.

    Returns:
        A 2-tuple of: (A human-readable script that Script can parse,
            A list of contextual information for tooltips, etc.)
    """
    if variables is None:
        variables = {}  # No mutable default value.
    # these are parseActions for pyparsing.
    def str_literal_to_hex(s, loc, toks):
        for i, t in enumerate(toks):
            toks[i] = ''.join(['0x', t.encode('hex')])
        return toks

    def var_name_to_value(s, loc, toks):
        for i, t in enumerate(toks):
            val = variables.get(t[1:])
            if val:
                toks[i] = val
        return toks

    def implicit_opcode_to_explicit(s, loc, toks):
        """Add "OP_" prefix to an opcode."""
        for i, t in enumerate(toks):
            toks[i] = '_'.join(['OP', t])
        return toks

    def hex_to_formatted_hex(s, loc, toks):
        """Add "0x" prefix and ensure even length."""
        for i, t in enumerate(toks):
            new_tok = t
            # Add '0x' prefix
            if not t.startswith('0x'):
                if t.startswith('x'):
                    new_tok = ''.join(['0', t])
                else:
                    new_tok = ''.join(['0x', t])
            # Even-length string
            if len(new_tok) % 2 != 0:
                new_tok = ''.join([new_tok[0:2], '0', new_tok[2:]])
            toks[i] = new_tok
        return toks

    # ^ parseActions for pyparsing end here.
    str_literal = QuotedString('"')
    str_literal.setParseAction(str_literal_to_hex)
    var_name = Combine(Word('$') + Word(pyparsing.alphas))
    var_name.setParseAction(var_name_to_value)

    # Here we populate the list of contextual tips.

    # Explicit opcode names
    op_names = [str(i) for i in OPCODE_NAMES.keys()]
    op_names_explicit = ' '.join(op_names)

    def is_small_int(op):
        """True if op is one of OP_1, OP_2, ...OP_16"""
        try:
            i = int(op[3:])
            return True
        except ValueError:
            return False

    op_names_implicit = ' '.join(
        [i[3:] for i in op_names if not is_small_int(i)])

    # Hex, implicit (e.g. 'a') and explicit (e.g. '0x0a')
    explicit_hex = Combine(
        Word('0x') + Word(pyparsing.hexnums) + pyparsing.WordEnd())
    implicit_hex = Combine(pyparsing.WordStart() +
                           OneOrMore(Word(pyparsing.hexnums)) +
                           pyparsing.WordEnd())
    explicit_hex.setParseAction(hex_to_formatted_hex)
    implicit_hex.setParseAction(hex_to_formatted_hex)

    # Opcodes, implicit (e.g. 'ADD') and explicit (e.g. 'OP_ADD')
    explicit_op = pyparsing.oneOf(op_names_explicit)
    implicit_op = Combine(pyparsing.WordStart() +
                          pyparsing.oneOf(op_names_implicit))
    implicit_op.setParseAction(implicit_opcode_to_explicit)

    contexts = pyparsing.Optional(
        var_name('Variable') | str_literal('String literal')
        | explicit_op('Opcode') | implicit_op('Opcode') | explicit_hex('Hex')
        | implicit_hex('Hex'))
    matches = [(i[0].asDict(), i[1], i[2]) for i in contexts.scanString(text)]
    context_tips = []
    for i in matches:
        d = i[0]
        if len(d.items()) == 0: continue
        match_type, value = d.items()[0]
        start = i[1]
        end = i[2]
        context_tips.append((start, end, value, match_type))

    # Now we do the actual transformation.

    s = text
    s = var_name.transformString(s)
    s = str_literal.transformString(s)
    s = implicit_op.transformString(s)
    s = implicit_hex.transformString(s)
    s = explicit_hex.transformString(s)
    return s, context_tips
Ejemplo n.º 5
0
def transform_human(text, variables=None):
    """Transform user input with given context.

    Args:
        text (str): User input.
        variables (dict): Variables for purposes of substitution.

    Returns:
        A 2-tuple of: (A human-readable script that Script can parse,
            A list of contextual information for tooltips, etc.)
    """
    if variables is None:
        variables = {} # No mutable default value.
    # these are parseActions for pyparsing.
    def str_literal_to_hex(s, loc, toks):
        for i, t in enumerate(toks):
            toks[i] = ''.join(['0x', t.encode('hex')])
        return toks
    def var_name_to_value(s, loc, toks):
        for i, t in enumerate(toks):
            val = variables.get(t[1:])
            if val:
                toks[i] = val
        return toks
    def implicit_opcode_to_explicit(s, loc, toks):
        """Add "OP_" prefix to an opcode."""
        for i, t in enumerate(toks):
            toks[i] = '_'.join(['OP', t])
        return toks
    def hex_to_formatted_hex(s, loc, toks):
        """Add "0x" prefix and ensure even length."""
        for i, t in enumerate(toks):
            new_tok = t
            # Add '0x' prefix
            if not t.startswith('0x'):
                if t.startswith('x'):
                    new_tok = ''.join(['0', t])
                else:
                    new_tok = ''.join(['0x', t])
            # Even-length string
            if len(new_tok) % 2 != 0:
                new_tok = ''.join([new_tok[0:2], '0', new_tok[2:]])
            toks[i] = new_tok
        return toks
    # ^ parseActions for pyparsing end here.
    str_literal = QuotedString('"')
    str_literal.setParseAction(str_literal_to_hex)
    var_name = Combine(Word('$') + Word(pyparsing.alphas))
    var_name.setParseAction(var_name_to_value)

    # Here we populate the list of contextual tips.

    # Explicit opcode names
    op_names = [str(i) for i in OPCODE_NAMES.keys()]
    op_names_explicit = ' '.join(op_names)
    def is_small_int(op):
        """True if op is one of OP_1, OP_2, ...OP_16"""
        try:
            i = int(op[3:])
            return True
        except ValueError:
            return False
    op_names_implicit = ' '.join([i[3:] for i in op_names if not is_small_int(i)])

    # Hex, implicit (e.g. 'a') and explicit (e.g. '0x0a')
    explicit_hex = Combine(Word('0x') + Word(pyparsing.hexnums) + pyparsing.WordEnd())
    implicit_hex = Combine(pyparsing.WordStart() + OneOrMore(Word(pyparsing.hexnums)) + pyparsing.WordEnd())
    explicit_hex.setParseAction(hex_to_formatted_hex)
    implicit_hex.setParseAction(hex_to_formatted_hex)

    # Opcodes, implicit (e.g. 'ADD') and explicit (e.g. 'OP_ADD')
    explicit_op = pyparsing.oneOf(op_names_explicit)
    implicit_op = Combine(pyparsing.WordStart() + pyparsing.oneOf(op_names_implicit))
    implicit_op.setParseAction(implicit_opcode_to_explicit)

    contexts = pyparsing.Optional(var_name('Variable') |
                                  str_literal('String literal') |
                                  explicit_op('Opcode') |
                                  implicit_op('Opcode') |
                                  explicit_hex('Hex') |
                                  implicit_hex('Hex'))
    matches = [(i[0].asDict(), i[1], i[2]) for i in contexts.scanString(text)]
    context_tips = []
    for i in matches:
        d = i[0]
        if len(d.items()) == 0: continue
        match_type, value = d.items()[0]
        start = i[1]
        end = i[2]
        context_tips.append( (start, end, value, match_type) )

    # Now we do the actual transformation.

    s = text
    s = var_name.transformString(s)
    s = str_literal.transformString(s)
    s = implicit_op.transformString(s)
    s = implicit_hex.transformString(s)
    s = explicit_hex.transformString(s)
    return s, context_tips
Ejemplo n.º 6
0
def eval_script(stack, scriptIn, debug=False):
    if len(scriptIn) > MAX_SCRIPT_SIZE:
        raise EvalScriptError(
            "script too large; got %d bytes; maximum %d bytes" %
            (len(scriptIn), MAX_SCRIPT_SIZE),
            stack=stack,
            scriptIn=scriptIn,
        )

    altstack = []
    vfExec = []
    pbegincodehash = 0
    nOpCount = [0]

    if debug:
        print("-- start script --")

    for (sop, sop_data, sop_pc) in scriptIn.raw_iter():
        fExec = _CheckExec(vfExec)

        if debug and (sop <= OP_PUSHDATA4 or fExec or
                      (OP_IF <= sop <= OP_ENDIF)):
            pp([s.hex() if type(s) == bytes else s for s in stack])
            print(OPCODE_NAMES.get(sop, sop))

        if sop in DISABLED_OPCODES:
            raise EvalScriptError

        if sop > OP_16:
            nOpCount[0] += 1
            if nOpCount[0] > MAX_SCRIPT_OPCODES:
                raise EvalScriptError

        def check_args(n):
            if len(stack) < n:
                raise EvalScriptError

        if sop <= OP_PUSHDATA4:
            if len(sop_data) > MAX_SCRIPT_ELEMENT_SIZE:
                raise EvalScriptError

            elif fExec:
                stack.append(sop_data)
                continue

        elif fExec or (OP_IF <= sop <= OP_ENDIF):

            if sop == OP_1NEGATE or ((sop >= OP_1) and (sop <= OP_16)):
                v = sop - (OP_1 - 1)
                stack.append(bitcoin.core._bignum.bn2vch(v))

            elif sop in _ISA_BINOP:
                _BinOp(sop, stack)

            elif sop in _ISA_UNOP:
                _UnaryOp(sop, stack)

            elif sop == OP_2DROP:
                check_args(2)
                stack.pop()
                stack.pop()

            elif sop == OP_2DUP:
                check_args(2)
                v1 = stack[-2]
                v2 = stack[-1]
                stack.append(v1)
                stack.append(v2)

            elif sop == OP_2OVER:
                check_args(4)
                v1 = stack[-4]
                v2 = stack[-3]
                stack.append(v1)
                stack.append(v2)

            elif sop == OP_2ROT:
                check_args(6)
                v1 = stack[-6]
                v2 = stack[-5]
                del stack[-6]
                del stack[-5]
                stack.append(v1)
                stack.append(v2)

            elif sop == OP_2SWAP:
                check_args(4)
                tmp = stack[-4]
                stack[-4] = stack[-2]
                stack[-2] = tmp

                tmp = stack[-3]
                stack[-3] = stack[-1]
                stack[-1] = tmp

            elif sop == OP_3DUP:
                check_args(3)
                v1 = stack[-3]
                v2 = stack[-2]
                v3 = stack[-1]
                stack.append(v1)
                stack.append(v2)
                stack.append(v3)

            elif sop == OP_CHECKMULTISIG or sop == OP_CHECKMULTISIGVERIFY:
                tmpScript = CScript(scriptIn[pbegincodehash:])
                _CheckMultiSig(sop, tmpScript, stack, nOpCount)

            elif sop == OP_CHECKSIG or sop == OP_CHECKSIGVERIFY:
                check_args(2)
                vchPubKey = stack[-1]
                vchSig = stack[-2]
                tmpScript = CScript(scriptIn[pbegincodehash:])

                # Drop the signature, since there's no way for a signature to sign itself
                #
                # Of course, this can only come up in very contrived cases now that
                # scriptSig and scriptPubKey are processed separately.
                tmpScript = FindAndDelete(tmpScript, CScript([vchSig]))

                ok = _CheckSig(vchSig, vchPubKey, tmpScript)
                if not ok and sop == OP_CHECKSIGVERIFY:
                    raise EvalScriptError

                else:
                    stack.pop()
                    stack.pop()

                    if ok:
                        if sop != OP_CHECKSIGVERIFY:
                            stack.append(b"\x01")
                    else:
                        # FIXME: this is incorrect, but not caught by existing
                        # test cases
                        stack.append(b"\x00")

            elif sop == OP_CODESEPARATOR:
                pbegincodehash = sop_pc

            elif sop == OP_DEPTH:
                bn = len(stack)
                stack.append(bitcoin.core._bignum.bn2vch(bn))

            elif sop == OP_DROP:
                check_args(1)
                stack.pop()

            elif sop == OP_DUP:
                check_args(1)
                v = stack[-1]
                stack.append(v)

            elif sop == OP_ELSE:
                if len(vfExec) == 0:
                    raise EvalScriptError
                vfExec[-1] = not vfExec[-1]

            elif sop == OP_ENDIF:
                if len(vfExec) == 0:
                    raise EvalScriptError
                vfExec.pop()

            elif sop == OP_EQUAL:
                check_args(2)
                v1 = stack.pop()
                v2 = stack.pop()

                if v1 == v2:
                    stack.append(b"\x01")
                else:
                    stack.append(b"")

            elif sop == OP_EQUALVERIFY:
                check_args(2)
                v1 = stack[-1]
                v2 = stack[-2]

                if v1 == v2:
                    stack.pop()
                    stack.pop()
                else:
                    raise EvalScriptError

            elif sop == OP_FROMALTSTACK:
                if len(altstack) < 1:
                    raise EvalScriptError
                v = altstack.pop()
                stack.append(v)

            elif sop == OP_HASH160:
                check_args(1)
                stack.append(bitcoin.core.serialize.Hash160(stack.pop()))

            elif sop == OP_HASH256:
                check_args(1)
                stack.append(bitcoin.core.serialize.Hash(stack.pop()))

            elif sop == OP_IF or sop == OP_NOTIF:
                val = False

                if fExec:
                    check_args(1)
                    vch = stack.pop()
                    val = _CastToBool(vch)
                    if sop == OP_NOTIF:
                        val = not val

                vfExec.append(val)

            elif sop == OP_IFDUP:
                check_args(1)
                vch = stack[-1]
                if _CastToBool(vch):
                    stack.append(vch)

            elif sop == OP_NIP:
                check_args(2)
                del stack[-2]

            elif sop == OP_NOP:
                pass

            elif sop >= OP_NOP1 and sop <= OP_NOP10:
                pass

            elif sop == OP_OVER:
                check_args(2)
                vch = stack[-2]
                stack.append(vch)

            elif sop == OP_PICK or sop == OP_ROLL:
                check_args(2)
                n = _CastToBigNum(stack.pop())
                if n < 0 or n >= len(stack):
                    raise EvalScriptError
                vch = stack[-n - 1]
                if sop == OP_ROLL:
                    del stack[-n - 1]
                stack.append(vch)

            elif sop == OP_RETURN:
                raise EvalScriptError

            elif sop == OP_RIPEMD160:
                check_args(1)

                h = hashlib.new("ripemd160")
                h.update(stack.pop())
                stack.append(h.digest())

            elif sop == OP_ROT:
                check_args(3)
                tmp = stack[-3]
                stack[-3] = stack[-2]
                stack[-2] = tmp

                tmp = stack[-2]
                stack[-2] = stack[-1]
                stack[-1] = tmp

            elif sop == OP_SIZE:
                check_args(1)
                bn = len(stack[-1])
                stack.append(bitcoin.core._bignum.bn2vch(bn))

            elif sop == OP_SHA1:
                check_args(1)
                stack.append(hashlib.sha1(stack.pop()).digest())

            elif sop == OP_SHA256:
                check_args(1)
                stack.append(hashlib.sha256(stack.pop()).digest())

            elif sop == OP_SWAP:
                check_args(2)
                tmp = stack[-2]
                stack[-2] = stack[-1]
                stack[-1] = tmp

            elif sop == OP_TOALTSTACK:
                check_args(1)
                v = stack.pop()
                altstack.append(v)

            elif sop == OP_TUCK:
                check_args(2)
                vch = stack[-1]
                stack.insert(len(stack) - 2, vch)

            elif sop == OP_VERIFY:
                check_args(1)
                v = _CastToBool(stack[-1])
                if v:
                    stack.pop()
                else:
                    raise EvalScriptError

            elif sop == OP_WITHIN:
                check_args(3)
                bn3 = _CastToBigNum(stack[-1])
                bn2 = _CastToBigNum(stack[-2])
                bn1 = _CastToBigNum(stack[-3])
                stack.pop()
                stack.pop()
                stack.pop()
                v = (bn2 <= bn1) and (bn1 < bn3)
                if v:
                    stack.append(b"\x01")
                else:
                    # FIXME: this is incorrect, but not caught by existing
                    # test cases
                    stack.append(b"\x00")

            else:
                raise EvalScriptError

        # size limits
        if len(stack) + len(altstack) > MAX_STACK_ITEMS:
            raise EvalScriptError

    # Unterminated IF/NOTIF/ELSE block
    if len(vfExec):
        raise EvalScriptError

    if debug:
        pp([s.hex() if type(s) == bytes else s for s in stack])
        print("-- end --")

    return stack
Ejemplo n.º 7
-1
    def do_step(self):
        """Returns whether another step can be done."""
        if self.step_counter == -1:
            txt = str(self.tx_script.toPlainText())
            scr = CScript(txt.decode('hex'))
            # So we can show the opcode in the stack log
            self.script_ops = [i for i in scr.raw_iter()]
            self.stack.set_script(scr, self.tx, self.inIdx)
            self.stack_iterator = self.stack.step()
            self.stack_log.clear()
            self.step_counter += 1

        step_again = False
        try:
            self.step_counter += 1
            stack_state, action = self.stack_iterator.next()
            new_stack = [i.encode('hex') for i in reversed(stack_state)]
            self.stack_view.clear()
            self.stack_view.addItems(new_stack)

            op_name = OPCODE_NAMES.get(self.script_ops[self.step_counter - 1][0], 'PUSHDATA')
            self.highlight_step(self.script_ops[self.step_counter - 1])
            item = QTreeWidgetItem(map(lambda i: str(i), [self.step_counter, op_name, action]))
            item.setTextAlignment(0, Qt.AlignLeft)
            item.setToolTip(1, 'Step {} operation'.format(self.step_counter))
            item.setToolTip(2, 'Result of step {}'.format(self.step_counter))
            self.stack_log.insertTopLevelItem(0, item)
            self.stack_result.setText(action)
            self.stack_result.setProperty('hasError', False)
            step_again = True
        except StopIteration:
            self.stack_result.setText('End of script.')
        except Exception as e:
            self.stack_result.setText(str(e))
            self.stack_result.setProperty('hasError', True)
        finally:
            self.style().polish(self.stack_result)

        return step_again