def __init__(self, tx, index): self.tx = tx self.index = index self.input = tx.inputs[index] self.output = self.input.ref() self.scriptPubKey = self.output.script self.scriptSig = self.input.script self.script = self.scriptSig + self.scriptPubKey self.stack = [] self.OPS = {OP(i): partial(self.OP_PUSH, i) for i in range(1, 76)} self.OPS.update( {OP(i): partial(self.push, i - 80) for i in range(81, 97)})
def depush(script: bytes) -> bytes: if len(script) == 0: raise ScriptValidationError('Empty script') push_byte, script = script[0], script[1:] op = OP(push_byte) if push_byte not in range(1, 76): raise ScriptValidationError( f'Script does not start with a PUSH opcode: {op}') if len(script) < push_byte: raise ScriptValidationError('Script too short') elif len(script) > push_byte: raise ScriptValidationError('Script too long') return script
def _receive(self, value: int): """Creates an output that sends to this address""" addr_type = self.type() output = Output(value=value, script=b'') if addr_type == ADDRESS.P2PKH: address = base58.decode(self.address).rjust(25, b'\x00') keyhash = address[1:-4] output.script = OP.DUP.byte + OP.HASH160.byte + push( keyhash) + OP.EQUALVERIFY.byte + OP.CHECKSIG.byte elif addr_type == ADDRESS.P2SH: address = base58.decode(self.address).rjust(25, b'\x00') scripthash = address[1:-4] output.script = OP.HASH160.byte + push(scripthash) + OP.EQUAL.byte elif addr_type in (ADDRESS.P2WPKH, ADDRESS.P2WSH): witness_version, witness_program = bech32.decode( network('hrp'), self.address) output.script = OP(bytes_to_int( witness_byte(witness_version))).byte + push( bytes(witness_program)) else: raise ValidationError(f"Cannot create output of type {addr_type}") return output
def asm(script): """Turns a script into a symbolic representation""" if isinstance(script, str): script = hex_to_bytes(script) else: script = copy(script) def read(n): nonlocal script data = script[:n] assert data or n == 0, 'EOF' script = script[n:] return data results = [] while script: byte = bytes_to_int(read(1)) op = OP(byte) if byte in range(1, 76): results.append(bytes_to_hex(read(byte))) else: results.append(str(op)) return ' '.join(results)
def step(self): """Executes one script operation""" byte = bytes_to_int(self.read(1)) opcode = OP(byte) self.op(opcode)