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
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
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
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
def test_op_hash160(self): stack = [b'hello world'] self.assertTrue(op_hash160(stack)) self.assertEqual(stack[0].hex(), 'd7d5ee7824ff93f94c3055af9382c86c68b5ca92')
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
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
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
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