示例#1
0
    def _walk_ast(self, ast):
        for a in ast:
            total_stack_size = len(self._stack) + len(self._alt_stack)
            if total_stack_size > 1000:
                raise ScriptInterpreterError(
                    "Too many items (%d) on the stack!" % total_stack_size)
            if self.stop:
                break

            opcode = None
            args = None
            if isinstance(a, list):
                opcode = a[0]
                args = a[1:]
            else:
                opcode = a

            if opcode in self.DISABLED_OPS + self.RESERVED_WORDS:
                self.stop = True
                break

            if opcode in Script.BTC_OPCODE_TABLE:
                op = Script.BTC_OPCODE_TABLE[opcode]
            else:
                op = None

            if opcode == "OP_0":
                self._op_0()
            elif isinstance(opcode, bytes):
                self._op_push(opcode)
            elif opcode in ['OP_PUSHDATA1', 'OP_PUSHDATA2', 'OP_PUSHDATA4']:
                pushlen = int(opcode[-1])
                if pushlen == 1:
                    datalen = args[0][0]
                elif pushlen == 2:
                    datalen = struct.unpack("<H", args[0])[0]
                elif pushlen == 4:
                    datalen = struct.unpack("<I", args[0])[0]
                data = args[1]
                if pushlen != (datalen.bit_length() + 7) // 8:
                    raise ScriptInterpreterError(
                        "datalen does not correspond with opcode")
                if len(data) != datalen:
                    raise ScriptInterpreterError("len(data) != datalen in %s" %
                                                 opcode)
                self._op_pushdata(datalen, data)
            elif op and op >= Script.BTC_OPCODE_TABLE['OP_1'] and \
                op <= Script.BTC_OPCODE_TABLE['OP_16']:
                self._op_pushnum(opcode)
            elif opcode in ['OP_IF', 'OP_NOTIF']:
                self._op_if(opcode, args)
            elif hasattr(self, "_" + opcode.lower()):
                f = getattr(self, "_" + opcode.lower())
                f()
示例#2
0
    def _op_endif(self):
        """ Ends an if/else block. All blocks must end, or the
            transaction is invalid. An OP_ENDIF without OP_IF earlier is
            also invalid.
        """
        if len(self._if_else_stack) == 0:
            self.stop = True
            raise ScriptInterpreterError("OP_ENDIF without OP_IF/NOTIF")

        self._if_else_stack.pop()
示例#3
0
    def _op_push(self, data):
        """ Next opcode bytes are pushed onto stack

        Args:
            data (bytes): Array of bytes of at least opcode length.
        """
        if len(data) < 0x01 or len(data) > 0x4b:
            raise ScriptInterpreterError(
                "data must only be between 1 and 75 bytes long")

        self._stack.append(data)
示例#4
0
 def _op_pick(self, roll=False):
     """ Copies the nth item in the stack to the top
     """
     self._check_stack_len(2)
     n = self._get_int()
     if n <= 0 or n >= len(self._stack):
         self.stop = True
         raise ScriptInterpreterError("n (%d) is invalid." % n)
     x = self._stack[-n]
     if roll:
         del self._stack[-n]
     self._stack.append(x)
示例#5
0
    def _op_else(self, data):
        """ If the preceding OP_IF or OP_NOTIF or OP_ELSE was not
            executed then these statements are and if the preceding OP_IF
            or OP_NOTIF or OP_ELSE was executed then these statements are
            not.
        """
        if len(self._if_else_stack) == 0:
            self.stop = True
            raise ScriptInterpreterError("In OP_ELSE without OP_IF/NOTIF")

        if not self._if_else_stack[-1]:
            self._walk_ast(data)
示例#6
0
    def _op_pushdata(self, datalen, data):
        """ Next byte(s) determines number of bytes that are pushed onto
            stack

        Args:
            datalen (int): Number of bytes to be pushed
            data (bytes): Array of bytes.
        """
        if len(data) < datalen:
            raise ScriptInterpreterError(
                "data should have at least %d bytes but has only %d." %
                (datalen, len(data)))

        self._stack.append(data)
示例#7
0
    def _check_stack_len(self, min_len, alt=False):
        """ Checks that the stack has a minimum number
            of elements.

        Args:
            min_len (int): The minimum number of elements
                that should be on the stack.
            alt (bool): If True, checks the altstack.

        Raises:
            ValueError: If the number of stack elements is fewer
                 than min_len.
        """
        s = self._alt_stack if alt else self._stack
        if len(s) < min_len:
            raise ScriptInterpreterError("Stack has fewer than %d operands." %
                                         min_len)
示例#8
0
    def _check_txn(self):
        """ Checks that a transaction object has been initialized
            in self._data.

        Raises:
            ValueError: If there is no Transaction object in self._data
        """
        from two1.lib.bitcoin.txn import Transaction
        if not isinstance(self._txn, Transaction):
            raise ScriptInterpreterError("No transaction found!")

        if self._input_index < 0 or self._input_index >= len(self._txn.inputs):
            raise ValueError("Invalid input index.")

        if self._sub_script is None:
            raise ValueError("sub_script must not be None.")

        if not isinstance(self._sub_script, Script):
            raise TypeError("sub_script must be a Script object.")
示例#9
0
    def _op_if(self, opcode, data):
        """ If the top stack value is not 0 (OP_IF) or 1 (OP_NOTIF),
            the statements are executed. The top stack value is
            removed.
        """
        self._check_stack_len(1)
        do = self._get_bool()
        if opcode == 'OP_NOTIF':
            do = not do

        if do:
            self._if_else_stack.append(do)
            self._walk_ast(data[0])
        elif len(data) == 3:
            self._if_else_stack.append(do)
            self._op_else(data[1])

        if data[-1] == "OP_ENDIF":
            if self._if_else_stack:
                self._op_endif()
        else:
            raise ScriptInterpreterError("No matching OP_ENDIF!")
示例#10
0
    def _op_checkmultisig(self, partial=False):
        """ Compares the first signature against each public key until
            it finds an ECDSA match. Starting with the subsequent public
            key, it compares the second signature against each remaining
            public key until it finds an ECDSA match. The process is
            repeated until all signatures have been checked or not enough
            public keys remain to produce a successful result. All
            signatures need to match a public key. Because public keys are
            not checked again if they fail any signature comparison,
            signatures must be placed in the scriptSig using the same
            order as their corresponding public keys were placed in the
            scriptPubKey or redeemScript. If all signatures are valid, 1
            is returned, 0 otherwise. Due to a bug, one extra unused value
            is removed from the stack.
        """
        self._check_stack_len(1)
        self._check_txn()

        num_keys = self._stack.pop()
        self._check_stack_len(num_keys)

        keys_bytes = []
        for i in range(num_keys):
            keys_bytes.insert(0, self._stack.pop())
        public_keys = [PublicKey.from_bytes(p) for p in keys_bytes]

        min_num_sigs = self._stack.pop()

        # Although "m" is the *minimum* number of required signatures, bitcoin
        # core only consumes "m" signatures and then expects an OP_0. This
        # means that if m < min_num_sigs <= n, bitcoin core will return a
        # script failure. See:
        # https://github.com/bitcoin/bitcoin/blob/0.10/src/script/interpreter.cpp#L840
        # We will do the same.
        hash_types = set()
        sigs = []
        for i in range(min_num_sigs):
            s = self._stack.pop()
            try:
                sig = Signature.from_der(s[:-1])
                hash_types.add(s[-1])
                sigs.insert(0, sig)
            except ValueError:
                if partial:
                    # Put it back on stack
                    self._stack.append(s)
                else:
                    # If not a partial evaluation there are not enough
                    # sigs
                    rv = False
                break

        if len(hash_types) != 1:
            raise ScriptInterpreterError(
                "Not all signatures have the same hash type!")

        hash_type = hash_types.pop()
        txn_copy = self._txn._copy_for_sig(input_index=self._input_index,
                                           hash_type=hash_type,
                                           sub_script=self._sub_script)

        msg = bytes(txn_copy) + utils.pack_u32(hash_type)
        txn_digest = hashlib.sha256(msg).digest()

        # Now we verify
        last_match = -1
        rv = True
        match_count = 0

        for sig in sigs:
            matched_any = False
            for i, pub_key in enumerate(public_keys[last_match + 1:]):
                if pub_key.verify(txn_digest, sig):
                    last_match = i
                    match_count += 1
                    matched_any = True
                    break

            if not matched_any:
                # Bail early if the sig couldn't be verified
                # by any public key
                rv = False
                break

        rv &= match_count >= min_num_sigs

        # Now make sure the last thing on the stack is OP_0
        if len(self._stack) == 1:
            rv &= self._stack.pop() == b''
            rv &= len(self._stack) == 0
        else:
            rv = False

        self._stack.append(rv)
        if partial:
            self.match_count = match_count