Esempio n. 1
0
 def evaluate(self, z):
     # create a copy as we may need to add to this list if we have a
     # RedeemScript
     instructions = self.instructions[:]
     stack = []
     altstack = []
     while len(instructions) > 0:
         instruction = instructions.pop(0)
         if type(instruction) == int:
             # do what the op code says
             operation = OP_CODE_FUNCTIONS[instruction]
             if instruction in (99, 100):
                 # op_if/op_notif require the instructions array
                 if not operation(stack, instructions):
                     print('bad op: {}'.format(OP_CODE_NAMES[instruction]))
                     return False
             elif instruction in (107, 108):
                 # op_toaltstack/op_fromaltstack require the altstack
                 if not operation(stack, altstack):
                     print('bad op: {}'.format(OP_CODE_NAMES[instruction]))
                     return False
             elif instruction in (172, 173, 174, 175):
                 # these are signing operations, they need a sig_hash
                 # to check against
                 if not operation(stack, z):
                     print('bad op: {}'.format(OP_CODE_NAMES[instruction]))
                     return False
             else:
                 if not operation(stack):
                     print('bad op: {}'.format(OP_CODE_NAMES[instruction]))
                     return False
         else:
             # add the instruction to the stack
             stack.append(instruction)
             if len(instructions) == 3 and instructions[0] == 0xa9 \
                 and type(instructions[1]) == bytes and len(instructions[1]) == 20 \
                 and instructions[2] == 0x87:
                 # we execute the next three op codes
                 instructions.pop()
                 h160 = instructions.pop()
                 instructions.pop()
                 if not op_hash160(stack):
                     return False
                 stack.append(h160)
                 if not op_equal(stack):
                     return False
                 # final result should be a 1
                 if not op_verify(stack):
                     print('bad p2sh h160')
                     return False
                 # hashes match! now add the RedeemScript
                 redeem_script = encode_varint(
                     len(instruction)) + instruction
                 stream = BytesIO(redeem_script)
                 instructions.extend(Script.parse(stream).instructions)
     if len(stack) == 0:
         return False
     if stack.pop() == b'':
         return False
     return True
 def evaluate(self, z):
     # create a copy as we may need to add to this list if we have a
     # RedeemScript
     cmds = self.cmds[:]
     stack = []
     altstack = []
     while len(cmds) > 0:
         cmd = cmds.pop(0)
         if type(cmd) == int:
             # do what the opcode says
             operation = OP_CODE_FUNCTIONS[cmd]
             if cmd in (99, 100):
                 # op_if/op_notif require the cmds array
                 if not operation(stack, cmds):
                     LOGGER.info('bad op: {}'.format(OP_CODE_NAMES[cmd]))
                     return False
             elif cmd in (107, 108):
                 # op_toaltstack/op_fromaltstack require the altstack
                 if not operation(stack, altstack):
                     LOGGER.info('bad op: {}'.format(OP_CODE_NAMES[cmd]))
                     return False
             elif cmd in (172, 173, 174, 175):
                 # these are signing operations, they need a sig_hash
                 # to check against
                 if not operation(stack, z):
                     LOGGER.info('bad op: {}'.format(OP_CODE_NAMES[cmd]))
                     return False
             else:
                 if not operation(stack):
                     LOGGER.info('bad op: {}'.format(OP_CODE_NAMES[cmd]))
                     return False
         # tag::source1[]
         else:
             stack.append(cmd)
             if len(cmds) == 3 and cmds[0] == 0xa9 \
                 and type(cmds[1]) == bytes and len(cmds[1]) == 20 \
                 and cmds[2] == 0x87:  # <1>
                 cmds.pop()  # <2>
                 h160 = cmds.pop()
                 cmds.pop()
                 if not op_hash160(stack):  # <3>
                     return False
                 stack.append(h160)
                 if not op_equal(stack):
                     return False
                 if not op_verify(stack):  # <4>
                     LOGGER.info('bad p2sh h160')
                     return False
                 redeem_script = encode_varint(len(cmd)) + cmd  # <5>
                 stream = BytesIO(redeem_script)
                 cmds.extend(Script.parse(stream).cmds)  # <6>
                 # end::source1[]
     if len(stack) == 0:
         return False
     if stack.pop() == b'':
         return False
     return True
Esempio n. 3
0
 def evaluate(self, z):
     instructions = self.instructions[:]
     stack = []
     altstack = []
     while len(instructions) > 0:
         instruction = instructions.pop(0)
         if type(instruction) == int:
             operation = OP_CODE_FUNCTIONS[instruction]
             if instruction in (99, 100):
                 if not operation(stack, instructions):
                     LOGGER.info('bad op: {}'.format(OP_CODE_NAMES[instruction]))
                     return False
             elif instruction in (107, 108):
                 if not operation(stack, altstack):
                     LOGGER.info('bad op: {}'.format(OP_CODE_NAMES[instruction]))
                     return False
             elif instruction in (172, 173, 174, 175):
                 if not operation(stack, z):
                     LOGGER.info('bad op: {}'.format(OP_CODE_NAMES[instruction]))
                     return False
             else:
                 if not operation(stack):
                     LOGGER.info('bad op: {}'.format(OP_CODE_NAMES[instruction]))
                     return False
         # tag::source1[]
         else:
             stack.append(instruction)
             if len(instructions) == 3 and instructions[0] == 0xa9 \
                 and type(instructions[1]) == bytes and len(instructions[1]) == 20 \
                 and instructions[2] == 0x87:  # <1>
                 instructions.pop()  # <2>
                 h160 = instructions.pop()
                 instructions.pop()
                 if not op_hash160(stack):  # <3>
                     return False
                 stack.append(h160)
                 if not op_equal(stack):
                     return False
                 if not op_verify(stack):  # <4>
                     LOGGER.info('bad p2sh h160')
                     return False
                 redeem_script = encode_varint(len(instruction)) + instruction  # <5>
                 stream = BytesIO(redeem_script)
                 instructions.extend(Script.parse(stream).instructions)  # <6>
                 # end::source1[]
     if len(stack) == 0:
         return False
     if stack.pop() == b'':
         return False
     return True
 def evaluate(self, z, witness):
     # create a copy as we may need to add to this list if we have a
     # RedeemScript
     cmds = self.cmds[:]
     stack = []
     altstack = []
     while len(cmds) > 0:
         cmd = cmds.pop(0)
         if type(cmd) == int:
             # do what the opcode says
             operation = OP_CODE_FUNCTIONS[cmd]
             if cmd in (99, 100):
                 # op_if/op_notif require the cmds array
                 if not operation(stack, cmds):
                     LOGGER.info('bad op: {}'.format(OP_CODE_NAMES[cmd]))
                     return False
             elif cmd in (107, 108):
                 # op_toaltstack/op_fromaltstack require the altstack
                 if not operation(stack, altstack):
                     LOGGER.info('bad op: {}'.format(OP_CODE_NAMES[cmd]))
                     return False
             elif cmd in (172, 173, 174, 175):
                 # these are signing operations, they need a sig_hash
                 # to check against
                 if not operation(stack, z):
                     LOGGER.info('bad op: {}'.format(OP_CODE_NAMES[cmd]))
                     return False
             else:
                 if not operation(stack):
                     LOGGER.info('bad op: {}'.format(OP_CODE_NAMES[cmd]))
                     return False
         else:
             # add the cmd to the stack
             stack.append(cmd)
             # p2sh rule. if the next three cmds are:
             # OP_HASH160 <20 byte hash> OP_EQUAL this is the RedeemScript
             # OP_HASH160 == 0xa9 and OP_EQUAL == 0x87
             if len(cmds) == 3 and cmds[0] == 0xa9 \
                 and type(cmds[1]) == bytes and len(cmds[1]) == 20 \
                 and cmds[2] == 0x87:
                 redeem_script = encode_varint(len(cmd)) + cmd
                 # we execute the next three opcodes
                 cmds.pop()
                 h160 = cmds.pop()
                 cmds.pop()
                 if not op_hash160(stack):
                     return False
                 stack.append(h160)
                 if not op_equal(stack):
                     return False
                 # final result should be a 1
                 if not op_verify(stack):
                     LOGGER.info('bad p2sh h160')
                     return False
                 # hashes match! now add the RedeemScript
                 redeem_script = encode_varint(len(cmd)) + cmd
                 stream = BytesIO(redeem_script)
                 cmds.extend(Script.parse(stream).cmds)
             # witness program version 0 rule. if stack cmds are:
             # 0 <20 byte hash> this is p2wpkh
             # tag::source3[]
             if len(stack) == 2 and stack[0] == b'' and len(stack[1]) == 20:  # <1>
                 h160 = stack.pop()
                 stack.pop()
                 cmds.extend(witness)
                 cmds.extend(p2pkh_script(h160).cmds)
             # end::source3[]
             # witness program version 0 rule. if stack cmds are:
             # 0 <32 byte hash> this is p2wsh
             # tag::source6[]
             if len(stack) == 2 and stack[0] == b'' and len(stack[1]) == 32:
                 s256 = stack.pop()  # <1>
                 stack.pop()  # <2>
                 cmds.extend(witness[:-1])  # <3>
                 witness_script = witness[-1]  # <4>
                 if s256 != sha256(witness_script):  # <5>
                     print('bad sha256 {} vs {}'.format
                         (s256.hex(), sha256(witness_script).hex()))
                     return False
                 stream = BytesIO(encode_varint(len(witness_script)) 
                     + witness_script)
                 witness_script_cmds = Script.parse(stream).cmds  # <6>
                 cmds.extend(witness_script_cmds)
             # end::source6[]
     if len(stack) == 0:
         return False
     if stack.pop() == b'':
         return False
     return True
Esempio n. 5
0
 def evaluate(self, z, witness):
     # create a copy as we may need to add to this list if we have a
     # RedeemScript
     instructions = self.instructions[:]
     stack = []
     altstack = []
     while len(instructions) > 0:
         instruction = instructions.pop(0)
         if type(instruction) == int:
             # do what the opcode says
             operation = OP_CODE_FUNCTIONS[instruction]
             if instruction in (99, 100):
                 # op_if/op_notif require the instructions array
                 if not operation(stack, instructions):
                     LOGGER.info('bad op: {}'.format(
                         OP_CODE_NAMES[instruction]))
                     return False
             elif instruction in (107, 108):
                 # op_toaltstack/op_fromaltstack require the altstack
                 if not operation(stack, altstack):
                     LOGGER.info('bad op: {}'.format(
                         OP_CODE_NAMES[instruction]))
                     return False
             elif instruction in (172, 173, 174, 175):
                 # these are signing operations, they need a sig_hash
                 # to check against
                 if not operation(stack, z):
                     LOGGER.info('bad op: {}'.format(
                         OP_CODE_NAMES[instruction]))
                     return False
             else:
                 if not operation(stack):
                     LOGGER.info('bad op: {}'.format(
                         OP_CODE_NAMES[instruction]))
                     return False
         else:
             # add the instruction to the stack
             stack.append(instruction)
             # p2sh rule. if the next three instructions are:
             # OP_HASH160 <20 byte hash> OP_EQUAL this is the RedeemScript
             # OP_HASH160 == 0xa9 and OP_EQUAL == 0x87
             if len(instructions) == 3 and instructions[0] == 0xa9 \
                 and type(instructions[1]) == bytes and len(instructions[1]) == 20 \
                 and instructions[2] == 0x87:
                 redeem_script = encode_varint(
                     len(instruction)) + instruction
                 # we execute the next three opcodes
                 instructions.pop()
                 h160 = instructions.pop()
                 instructions.pop()
                 if not op_hash160(stack):
                     return False
                 stack.append(h160)
                 if not op_equal(stack):
                     return False
                 # final result should be a 1
                 if not op_verify(stack):
                     LOGGER.info('bad p2sh h160')
                     return False
                 # hashes match! now add the RedeemScript
                 redeem_script = encode_varint(
                     len(instruction)) + instruction
                 stream = BytesIO(redeem_script)
                 instructions.extend(Script.parse(stream).instructions)
             # witness program version 0 rule. if stack instructions are:
             # 0 <20 byte hash> this is p2wpkh
             if len(stack) == 2 and stack[0] == b'' and len(stack[1]) == 20:
                 h160 = stack.pop()
                 stack.pop()
                 instructions.extend(witness)
                 instructions.extend(p2pkh_script(h160).instructions)
             # witness program version 0 rule. if stack instructions are:
             # 0 <32 byte hash> this is p2wsh
             if len(stack) == 2 and stack[0] == b'' and len(stack[1]) == 32:
                 h256 = stack.pop()
                 stack.pop()
                 instructions.extend(witness[:-1])
                 witness_script = witness[-1]
                 if h256 != sha256(witness_script):
                     LOGGER.info('bad sha256 {} vs {}'.format(
                         h256.hex(),
                         sha256(witness_script).hex()))
                     return False
                 # hashes match! now add the Witness Script
                 stream = BytesIO(
                     encode_varint(len(witness_script)) + witness_script)
                 witness_script_instructions = Script.parse(
                     stream).instructions
                 instructions.extend(witness_script_instructions)
     if len(stack) == 0:
         return False
     if stack.pop() == b'':
         return False
     return True
Esempio n. 6
0
 def evaluate(self, z):
     # create a copy as we may need to add to this list if we have a
     # RedeemScript
     commands = self.commands[:]
     stack = []
     altstack = []
     while len(commands) > 0:
         command = commands.pop(0)
         if type(command) == int:
             # do what the op code says
             operation = OP_CODE_FUNCTIONS[command]
             if command in (99, 100):
                 # op_if/op_notif require the commands array
                 if not operation(stack, commands):
                     print('bad op: {}'.format(OP_CODE_NAMES[command]))
                     return False
             elif command in (107, 108):
                 # op_toaltstack/op_fromaltstack require the altstack
                 if not operation(stack, altstack):
                     print('bad op: {}'.format(OP_CODE_NAMES[command]))
                     return False
             elif command in (172, 173, 174, 175):
                 # these are signing operations, they need a sig_hash
                 # to check against
                 if not operation(stack, z):
                     print('bad op: {}'.format(OP_CODE_NAMES[command]))
                     return False
             else:
                 if not operation(stack):
                     print('bad op: {}'.format(OP_CODE_NAMES[command]))
                     return False
         else:
             # add the command to the stack
             stack.append(command)
             # p2sh rule. if the next three commands are:
             # OP_HASH160 <20 byte hash> OP_EQUAL this is the RedeemScript
             # OP_HASH160 == 0xa9 and OP_EQUAL == 0x87
             if len(commands) == 3 and commands[0] == 0xa9 \
                 and type(commands[1]) == bytes and len(commands[1]) == 20 \
                 and commands[2] == 0x87:
                 redeem_script = encode_varstr(command)
                 # we execute the next three op codes
                 commands.pop()
                 h160 = commands.pop()
                 commands.pop()
                 if not op_hash160(stack):
                     return False
                 stack.append(h160)
                 if not op_equal(stack):
                     return False
                 # final result should be a 1
                 if not op_verify(stack):
                     print('bad p2sh h160')
                     return False
                 # hashes match! now add the RedeemScript
                 stream = BytesIO(redeem_script)
                 commands.extend(Script.parse(stream).commands)
     if len(stack) == 0:
         return False
     if stack.pop() == b'':
         return False
     return True
Esempio n. 7
0
    def evaluate(self, z, witness=None):
        # create a copy as we may need to add to this list if we have a
        # RedeemScript
        cmds = self.cmds[:]
        stack = []
        altstack = []
        while len(cmds) > 0:
            cmd = cmds.pop(0)
            if type(cmd) == int:
                # do what the opcode says
                operation = OP_CODE_FUNCTIONS[cmd]
                if cmd in (99, 100):
                    # op_if/op_notif require the cmds array
                    if not operation(stack, cmds):
                        LOGGER.info('bad op: {}'.format(OP_CODE_NAMES[cmd]))
                        return False
                elif cmd in (107, 108):
                    # op_toaltstack/op_fromaltstack require the altstack
                    if not operation(stack, altstack):
                        LOGGER.info('bad op: {}'.format(OP_CODE_NAMES[cmd]))
                        return False
                elif cmd in (172, 173, 174, 175):
                    # these are signing operations, they need a sig_hash
                    # to check against
                    if not operation(stack, z):
                        LOGGER.info('bad op: {}'.format(OP_CODE_NAMES[cmd]))
                        return False
                else:
                    if not operation(stack):
                        LOGGER.info('bad op: {}'.format(OP_CODE_NAMES[cmd]))
                        return False
            else:
                # add the cmd to the stack
                stack.append(cmd)
                # p2sh rule: if the next 3 cmds are: OP_HASH160 (0xa9) <20 byte hash> OP_EQUAL (0x87) this is redeemScript
                if len(cmds) == 3 and cmds[0] == 0xa9 \
                    and type(cmds[1]) == bytes and len(cmds[1]) == 20 \
                    and cmds[2] == 0x87:
                    # we execute the next three opcodes
                    cmds.pop()
                    h160 = cmds.pop()
                    cmds.pop()
                    if not op_hash160(stack):
                        return False
                    stack.append(h160)
                    if not op_equal(stack):
                        return False
                    # final result should be a 1
                    if not op_verify(stack):
                        LOGGER.info('bad p2sh h160')
                        return False
                    # hashes match! now add the RedeemScript
                    redeem_script = encode_varint(len(cmd)) + cmd
                    stream = BytesIO(redeem_script)
                    cmds.extend(Script.parse(stream).cmds)
                # Witness program v0 rule: if stack cmds are: 0 <20 byte hash> this is p2wpkh
                if len(stack) == 2 and stack[0] in [b'', b'\x00'] and type(
                        stack[1]) == bytes and len(stack[1]) == 20:
                    h160 = stack.pop()
                    stack.pop()
                    cmds.extend(witness)
                    cmds.extend(p2pkh_script(h160).cmds)

        if len(stack) == 0:
            return False
        if stack.pop() == b'':
            return False
        return True
Esempio n. 8
0
def evaluate(commands, z, witness):
    cmds = commands[:]  # create a copy as we may need to add to this list if we have a redeem_script
    stack = []
    altstack = []
    while len(cmds) > 0:
        cmd = cmds.pop(0)
        if type(cmd) == int:
            # do what the opcode says
            operation = op.OP_CODE_FUNCTIONS[cmd]
            if cmd in (99, 100):
                # op_if/op_notif require the cmds array
                if not operation(stack, cmds):
                    LOGGER.info('bad op: {}'.format(op.OP_CODE_NAMES[cmd]))
                    return False
            elif cmd in (107, 108):
                # op_toaltstack/op_fromaltstack require the altstack
                if not operation(stack, altstack):
                    LOGGER.info('bad op: {}'.format(op.OP_CODE_NAMES[cmd]))
                    return False
            elif cmd in (172, 173, 174, 175):
                # these are signing operations, they need a sig_hash
                # to check against
                if not operation(stack, z):
                    LOGGER.info('bad op: {}'.format(op.OP_CODE_NAMES[cmd]))
                    return False
            else:
                if not operation(stack):
                    LOGGER.info('bad op: {}'.format(op.OP_CODE_NAMES[cmd]))
                    return False
        else:
            # add the cmd to the stack
            stack.append(cmd)
            # p2sh rule. if the next three cmds are:
            # OP_HASH160 <20 byte hash> OP_EQUAL this is the RedeemScript
            # OP_HASH160 == 0xa9 and OP_EQUAL == 0x87
            if len(cmds) == 3 and cmds[0] == 0xa9 \
                    and type(cmds[1]) == bytes and len(cmds[1]) == 20 \
                    and cmds[2] == 0x87:
                # we execute the next three opcodes
                cmds.pop()
                h160 = cmds.pop()
                cmds.pop()
                if not op.op_hash160(stack):
                    return False
                stack.append(h160)
                if not op.op_equal(stack):
                    return False
                # final result should be a 1
                if not op.op_verify(stack):
                    LOGGER.info('bad p2sh h160')
                    return False
                raw_redeem_script = util.encode_varint(len(cmd)) + cmd
                _, redeem_script = parse(BytesIO(raw_redeem_script))
                cmds.extend(redeem_script)
            # witness program version 0 rule. if stack cmds are [0 <20 byte hash>] this is p2wpkh
            if len(stack) == 2 and stack[0] == b'' and len(stack[1]) == 20:
                h160 = stack.pop()
                stack.pop()
                cmds.extend(witness)
                cmds.extend(p2pkh_script(h160))
            # witness program version 0 rule. if stack cmds are:[0 <32 byte hash>] this is p2wsh
            if len(stack) == 2 and stack[0] == b'' and len(stack[1]) == 32:
                s256 = stack.pop()
                stack.pop()
                cmds.extend(witness[:-1])
                raw_witness_script = witness[-1]
                if s256 != util.sha256(raw_witness_script):
                    print('bad sha256 {} vs {}'.format(
                        s256.hex(),
                        util.sha256(raw_witness_script).hex()))
                    return False
                stream = BytesIO(
                    util.encode_varint(len(raw_witness_script)) +
                    raw_witness_script)
                cmds.extend(parse(stream))
    if len(stack) == 0:
        return False
    if stack.pop() == b'':
        return False
    return True
Esempio n. 9
0
 def evaluate(self, z, witness, version=None, locktime=None, sequence=None):
     # get a copy of the commands array.
     cmds = self.cmds.copy()
     stack = []
     altstack = []
     # execute until commands array is empty.
     while len(cmds) > 0:
         cmd = cmds.pop(0)
         print("cmd", cmd)
         # if command is an opcode.
         if type(cmd) == int:
             # get the function that executes the opcode from the OP_CODE_FUNCTIONS array.
             operation = OP_CODE_FUNCTIONS[cmd]
             # 99 and 100 are OP_IF and OP_NOTIF. They require manipulations of the cmds array based on
             # the top element of the stack.
             if cmd in (99, 100):
                 # if executing the opcode returns False (fails)
                 if not operation(stack, cmds):
                     LOGGER.info(f"bad op: {OP_CODE_NAMES[cmd]}")
                     return False
             # 107 and 108 are OP_TOALTSTACK and OP_FROMALTSTACK respectively. They move stack elements
             # to an alternate stack (altstack)
             elif cmd in (107, 108):
                 # if executing the opcode returns False (fails)
                 if not operation(stack, altstack):
                     LOGGER.info(f"bad op: {OP_CODE_NAMES[cmd]}")
                     return False
             # 172, 173, 174 and 175 are OP_CHECKSIG, OP_CHECKSIGVERIFY, OP_CHECKMULTISIG and OP_CHECKMULTISIGVERIFY
             # all require the signature hash z for validation.
             elif cmd in (172, 173, 174, 175):
                 # if executing the opcode returns False (fails)
                 if not operation(stack, z):
                     LOGGER.info(f"bad op: {OP_CODE_NAMES[cmd]}")
                     return False
             # 177 is OP_CHECKLOCKTIMEVERIFY. Requires locktime and sequence.
             elif cmd == 177:
                 # if executing the opcode returns False (fails)
                 if not operation(stack, locktime, sequence):
                     LOGGER.info(f"bad op: {OP_CODE_NAMES[cmd]}")
                     return False
             # 177 is OP_CHECKSEQUENCEVERIFY. Requires sequence and version.
             elif cmd == 178:
                 # if executing the opcode returns False (fails)
                 if not operation(stack, version, sequence):
                     LOGGER.info(f"bad op: {OP_CODE_NAMES[cmd]}")
                     return False
             else:
                 # if executing the opcode returns False (fails)
                 if not operation(stack):
                     LOGGER.info(f"bad op: {OP_CODE_NAMES[cmd]}")
                     return False
         # if cmd is not an opcode, it's an element. We push it to the stack.
         else:
             stack.append(cmd)
             # We check if the commands follow the p2wsh special rule.
             if len(stack) == 2 and stack[0] == b'' and len(stack[1]) == 32:
                 # The top element is the sha256 hash of the WitnessScript.
                 s256 = stack.pop()
                 # The second element is the witness version.
                 stack.pop()
                 # Everything but the WitnessScript is added to the command set.
                 cmds.extend(witness[:-1])
                 witness_script = witness[-1]
                 s256_calculated = sha256(witness_script)
                 if s256 != s256_calculated:
                     print(
                         f"Bad sha256 {s256.hex()} vs. {s256_calculated.hex()}"
                     )
                     return False
                 stream = BytesIO(
                     encode_varint(len(witness_script)) + witness_script)
                 witness_script_cmds = Script.parse(stream).cmds
                 cmds.extend(witness_script_cmds)
             # We check if the commands follow the p2wpkh special rule - page 235.
             if len(stack) == 2 and stack[0] == b'' and len(stack[1]) == 20:
                 h160 = stack.pop()
                 stack.pop()
                 cmds.extend(witness)
                 cmds.extend(p2pkh_script(h160).cmds)
             # we check if next commands form the pattern that executes the special p2sh rule - page 152 and 156.
             # if that is the case, the last cmd appended would be the RedeemScript, which is an element.
             # That's why we check for the next 3 commands only.
             # Specifically, we check that they are: OP_HASH160 (0xa9), a hash element and OP_EQUAL(0x87).
             if len(cmds) == 3 and cmds[0] == 0xa9 and type(
                     cmds[1]) == bytes and len(
                         cmds[1]) == 20 and cmds[2] == 0x87:
                 # we run the sequence manually.
                 cmds.pop()
                 # the only value we need to save is the hash, the other two we know are OP_HASH160 and OP_EQUAL.
                 h160 = cmds.pop()
                 cmds.pop()
                 # first we perform the op_hash160 on the current stack, which hashes the top element of the stack.
                 if not op_hash160(stack):
                     return False
                 # then we push the hash160 we got in the commands to the stack.
                 stack.append(h160)
                 # next we perform an op_equal, which compares the 2 top most elements of the stack.
                 if not op_equal(stack):
                     return False
                 # next we need to check if the element left on the stack is a 1, which is what op_verify does.
                 if not op_verify(stack):
                     LOGGER.info('bad p2sh h160')
                     return False
                 # if we got to this point, we know cmd is the RedeemScrtipt.
                 # to be able to parse it, we need to prepend its length.
                 redeem_script = encode_varint(len(cmd)) + cmd
                 # we convert the script into a stream of bytes.
                 stream = BytesIO(redeem_script)
                 # we get the parsed script
                 parsed_script = Script.parse(stream)
                 # we extend the commands set with the commands from the parsed RedeemScript.
                 cmds.extend(parsed_script.cmds)
     # if stack is empty after running all the commands, we fail the script returning False.
     if len(stack) == 0:
         return False
     # if the stack's top element is an empty byte, which is how the stack stores a 0, we fail the script.
     if stack.pop() == b'':
         return False
     # any other result means the script is valid.
     return True
Esempio n. 10
0
    def evaluate(self, z, witness):
        # create a copy as we may need to add to this list if we have a
        # RedeemScript
        cmds = self.cmds[:]
        stack = []
        altstack = []
        while len(cmds) > 0:
            cmd = cmds.pop(0)
            if type(cmd) == int:
                # do what the opcode says
                # retrieving the function in op.py corresponding to the opcode
                operation = OP_CODE_FUNCTIONS[cmd]
                if cmd in (99, 100):
                    # op_if/op_notif require the cmds array
                    if not operation(stack, cmds):
                        LOGGER.info('bad op: {}'.format(OP_CODE_NAMES[cmd]))
                        return False
                elif cmd in (107, 108):
                    # op_toaltstack/op_fromaltstack require the altstack
                    if not operation(stack, altstack):
                        LOGGER.info('bad op: {}'.format(OP_CODE_NAMES[cmd]))
                        return False
                elif cmd in (172, 173, 174, 175):
                    # these are signing operations, they need a sig_hash
                    # to check against
                    if not operation(stack, z):
                        LOGGER.info('bad op: {}'.format(OP_CODE_NAMES[cmd]))
                        return False
                else:
                    if not operation(stack):
                        LOGGER.info('bad op: {}'.format(OP_CODE_NAMES[cmd]))
                        return False
            else:
                # add the cmd to the stack
                stack.append(cmd)
                # Determine whether this is a p2sh:
                # To do so, you need to look at the next three items in the command set.
                # Are there only three items remaining in the command set and are theY:
                # 0xa9 --op_hash160, 20 bytes--for the script hash and 0x87--op_equal?
                if len(cmds) == 3 and cmds[0] == 0xa9 and type(cmds[1]) == bytes and len(cmds[1]) == 20 and cmds[2] == 0x87:  # <1>
                    cmds.pop()  # <2>
                    h160 = cmds.pop()
                    cmds.pop()
                    if not op.op_hash160(stack):  # <3>
                        return False
                    stack.append(h160)
                    if not op.op_equal(stack):
                        return False
                    if not op.op_verify(stack):  # <4>
                        LOGGER.info('bad p2sh h160')
                        return False
                    redeem_script = encode_varint(len(cmd)) + cmd  # <5>
                    stream = BytesIO(redeem_script)
                    cmds.extend(Script.parse(stream).cmds)  # <6>
                # Determine whether this is a p2wpkh. 
                # To do so, you need to look at the stack (remember focus on the stack now, not the command set).
                # Are there only two items on the stack?  is the first b'' and the second 20 bytes?
                # The 20 bytes will be the hash of the witness field.
                # If so, then use the witness field and the hash on the stack to build a p2pkh command set.
                if len(stack) == 2 and stack[0] == b'' and len(stack[1]) == 20:
                    h160 = stack.pop()
                    stack.pop()
                    # witness should be two items, the signature and the public key (in bytes not BASE58)
                    cmds.extend(witness)
                    # the build out the command set with the p2pkh commands
                    cmds.extend(p2pkh_script(h160).cmds)
                    # now we have the p2pkh command set and the script evaluation proceeds...
                # Determine whether this is a p2wsh:
                # Does stack have just two items, b'' and a 32 byte hash-which hash is the witness script hash.
                # If so, check that the hash of the witness script equals the witness script hash 
                # that is already on the stack.  If so, build a command set starting with the witness filed items 
                # and then parse the witness script.  Append the parsed witness script items to the command set.
                # The p2wsh is often used for the segwit form of the m of n multisig.
                if len(stack) == 2 and stack[0] == b'' and type(stack[1]) == bytes and len(stack[1])==32:
                    s256 = stack.pop()
                    stack.pop()
                    witness_script = witness[-1]
                    if s256 != sha256(witness_script):
                        print('bad sha256 {} vs {}'.format(s256.hex(), sha256(witness_script).hex()))
                        return False
                    # If the wintess script checks out then add the witness fields to the command set--leaving the 
                    # witness script item to be parsed still
                    cmds.extend(witness[:-1])
                    # Parse the witness script--prepare it as a raw script and make into a stream first.
                    witness_script = encode_varint(len(witness_script)) + witness_script
                    witness_stream = BytesIO(witness_script)
                    witness_script_cmds = Script.parse(witness_stream).cmds
                    # Add the witness script items to the command set--these should be the script_pub_key
                    # items from a regular p2sh script_pub_key--which would be the m of n multisig.
                    cmds.extend(witness_script_cmds)

        if len(stack) == 0:
            return False
        if stack.pop() == b'':
            return False
        return True