def address_type(addr): if addr.startswith(('1', '2', '3', 'm', 'n')): try: address = base58.decode(addr).rjust(25, b'\x00') except Base58DecodeError as e: raise InvalidAddress(f"{addr} : {e}") from None payload, checksum = address[:-4], address[-4:] version_byte, digest = payload[0:1], payload[1:].rjust(20, b'\x00') if len(digest) != 20: raise InvalidAddress(f"{addr} : Bad Payload") from None if sha256(sha256(payload))[:4] != checksum: raise InvalidAddress(f"{addr} : Invalid checksum") from None try: return {network('keyhash'): ADDRESS.P2PKH, network('scripthash'): ADDRESS.P2SH}[version_byte] except KeyError: raise InvalidAddress(f"{addr} : Invalid version byte") from None elif addr.startswith(network('hrp')): try: witness_version, witness_program = bech32.decode(network('hrp'), addr) except Bech32DecodeError as e: raise InvalidAddress(f"{addr} : {e}") from None if not witness_version == 0x00: raise InvalidAddress(f"{addr} : Invalid witness version") from None if len(witness_program) == 20: return ADDRESS.P2WPKH elif len(witness_program) == 32: return ADDRESS.P2WSH else: raise InvalidAddress(f"{addr} : Invalid witness program") from None else: raise InvalidAddress(f"{addr} : Invalid leading character") from None
def test_bech32_decode(self): private, public = generate_keypair() witprog = hash160(public.encode(compressed=True)) address = bech32.encode(self.hrp, self.witver, witprog) wv, decoded = bech32.decode(self.hrp, address) self.assertEqual(wv, self.witver) self.assertEqual(bytes(decoded), bytes(witprog))
def address_to_script(addr: str) -> bytes: """https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#segwit-address-format""" hrp, _ = bech32.bech32_decode(addr) if hrp not in [net['hrp'] for net in networks.values()]: raise Bech32DecodeError('Invalid human-readable part') witver, witprog = bech32.decode(hrp, addr) if not (0 <= witver <= 16): raise Bech32DecodeError('Invalid witness version') script = witness_byte(witver) + push(bytes(witprog)) 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