def test_p2wpkh() -> None: # https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki # leading/trailing spaces should be tolerated pub = " 02 79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798" addr = "bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4" assert addr == b32.p2wpkh(pub) addr = "tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx" assert addr == b32.p2wpkh(pub, "testnet") # http://bitcoinscri.pt/pages/segwit_native_p2wpkh pub = "02 530c548d402670b13ad8887ff99c294e67fc18097d236d57880c69261b42def7" addr = "bc1qg9stkxrszkdqsuj92lm4c7akvk36zvhqw7p6ck" assert addr == b32.p2wpkh(pub) _, wit_prg, _ = b32.witness_from_address(addr) assert wit_prg == hash160(pub) uncompr_pub = bytes_from_point(point_from_octets(pub), compressed=False) err_msg = "not a private or compressed public key: " with pytest.raises(BTClibValueError, match=err_msg): b32.p2wpkh(uncompr_pub) with pytest.raises(BTClibValueError, match=err_msg): b32.p2wpkh(pub + "00") err_msg = "invalid size: " with pytest.raises(BTClibValueError, match=err_msg): b32.address_from_witness(0, hash160(pub) + b"\x00")
def test_address_witness() -> None: wit_ver = 0 wit_prg = 20 * b"\x05" for net in ("mainnet", "testnet"): addr = b32.address_from_witness(wit_ver, wit_prg, net) assert (wit_ver, wit_prg, net) == b32.witness_from_address(addr) wit_ver = 0 wit_prg = 32 * b"\x05" for net in ("mainnet", "testnet"): addr = b32.address_from_witness(wit_ver, wit_prg, net) assert (wit_ver, wit_prg, net) == b32.witness_from_address(addr) addr = "bc1qg9stkxrszkdqsuj92lm4c7akvk36zvhqw7p6ck" assert b32.address_from_witness(*b32.witness_from_address(addr)) == addr wit_prg_ints = list(wit_prg) wit_prg_ints[0] = -1 with pytest.raises(BTClibValueError, match="invalid value: "): b32.power_of_2_base_conversion(wit_prg_ints, 8, 5) addr = "tb1qq5zs2pg9q5zs2pg9q5zs2pg9q5zs2pg9q5mpvsef" err_msg = "invalid size: " with pytest.raises(BTClibValueError, match=err_msg): b32.witness_from_address(addr)
def test_non_standard_script_in_p2wsh() -> None: network = "mainnet" fed_pub_keys: List[Command] = ["00" * 33, "11" * 33, "22" * 33] rec_pub_keys: List[Command] = ["77" * 33, "88" * 33, "99" * 33] # fmt: off redeem_script_cmds: List[Command] = [ "OP_IF", "OP_2", *fed_pub_keys, "OP_3", "OP_CHECKMULTISIG", # noqa E131 "OP_ELSE", 500, "OP_CHECKLOCKTIMEVERIFY", "OP_DROP", # noqa E131 "OP_2", *rec_pub_keys, "OP_3", "OP_CHECKMULTISIG", # noqa E131 "OP_ENDIF", ] # fmt: on redeem_script = serialize(redeem_script_cmds) assert redeem_script_cmds == parse(redeem_script) payload = sha256(redeem_script) script_pub_key = ( "00207b5310339c6001f75614daa5083839fa54d46165f6c56025cc54d397a85a5708") assert script_pub_key == ScriptPubKey.p2wsh(redeem_script).script.hex() addr = "bc1q0df3qvuuvqqlw4s5m2jsswpelf2dgct97mzkqfwv2nfe02z62uyq7n4zjj" assert addr == address(script_pub_key, network) assert addr == b32.address_from_witness(0, payload, network)
def test_p2wsh() -> None: # self-consistency pub_key = "02 cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaf" redeem_script = ScriptPubKey.p2pkh(pub_key).script payload = sha256(redeem_script) script_pub_key = serialize(["OP_0", payload]) assert_p2wsh(script_pub_key) assert script_pub_key == ScriptPubKey.p2wsh(redeem_script).script assert ("p2wsh", payload) == type_and_payload(script_pub_key) # bech32 address network = "mainnet" addr = b32.p2wsh(redeem_script, network) assert addr == address(script_pub_key, network) assert addr == b32.address_from_witness(0, payload, network) # back from the address to the script_pub_key assert script_pub_key == ScriptPubKey.from_address(addr).script assert network == ScriptPubKey.from_address(addr).network # p2sh-wrapped base58 address addr = b58.p2wsh_p2sh(redeem_script, network) assert addr == "39GUePMSQ4mADpihVLd8cFQ2tih9Fy4qkz" err_msg = "invalid witness version: " with pytest.raises(BTClibValueError, match=err_msg): assert_p2wsh(b"\x33" + script_pub_key[1:]) err_msg = "invalid redeem script hash length marker: " with pytest.raises(BTClibValueError, match=err_msg): assert_p2wsh(script_pub_key[:1] + b"\x00" + script_pub_key[2:])
def test_p2wpkh() -> None: # self-consistency pub_key = "02 cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaf" payload = hash160(pub_key) script_pub_key = serialize(["OP_0", payload]) assert_p2wpkh(script_pub_key) assert script_pub_key == ScriptPubKey.p2wpkh(pub_key).script assert ("p2wpkh", payload) == type_and_payload(script_pub_key) # bech32 address network = "mainnet" addr = b32.p2wpkh(pub_key, network) assert addr == address(script_pub_key, network) assert addr == b32.address_from_witness(0, payload, network) # back from the address to the script_pub_key assert script_pub_key == ScriptPubKey.from_address(addr).script assert network == ScriptPubKey.from_address(addr).network # p2sh-wrapped base58 address addr = b58.p2wpkh_p2sh(pub_key, network) assert addr == "3BJxz2r8zY7LxJfdGjUpjjHNh6YEiitvf2" err_msg = "invalid witness version: " with pytest.raises(BTClibValueError, match=err_msg): assert_p2wpkh(b"\x33" + script_pub_key[1:]) err_msg = "invalid pub_key hash length marker: " with pytest.raises(BTClibValueError, match=err_msg): assert_p2wpkh(script_pub_key[:1] + b"\x00" + script_pub_key[2:])
def address(script_pub_key: Octets, network: str = "mainnet") -> str: "Return the bech32/base58 address from a script_pub_key." if script_pub_key: script_type, payload = type_and_payload(script_pub_key) if script_type in ("p2pkh", "p2sh"): return b58.address_from_h160(script_type, payload, network) if script_type in ("p2wsh", "p2wpkh"): return b32.address_from_witness(0, payload, network) if script_type == "p2tr": return b32.address_from_witness(1, payload, network) # not script_pub_key # or # script_type in ("p2pk", "p2ms", "nulldata", "unknown") return ""
def test_valid_address() -> None: "Test whether valid addresses decode to the correct output." valid_bc_addresses: List[Tuple[str, str]] = [ ( "BC1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KV8F3T4", "0014751e76e8199196d454941c45d1b3a323f1433bd6", ), ( "bc1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7kt5nd6y", "5128751e76e8199196d454941c45d1b3a323f1433bd6751e76e8199196d454941c45d1b3a323f1433bd6", ), ("BC1SW50QGDZ25J", "6002751e"), ( "bc1zw508d6qejxtdg4y5r3zarvaryvaxxpcs", "5210751e76e8199196d454941c45d1b3a323", ), ( "bc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vqzk5jj0", "512079be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798", ), ] valid_tb_addresses: List[Tuple[str, str]] = [ ( "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7", "00201863143c14c5166804bd19203356da136c985678cd4d27a1b8c6329604903262", ), ( "tb1qqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesrxh6hy", "0020000000c4a5cad46221b2a187905e5266362b99d5e91c6ce24d165dab93e86433", ), ( "tb1pqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesf3hn0c", "5120000000c4a5cad46221b2a187905e5266362b99d5e91c6ce24d165dab93e86433", ), ] for address, hexscript in valid_bc_addresses + valid_tb_addresses: addr = b32.address_from_witness(*b32.witness_from_address(address)) assert address.lower().strip() == addr wit_ver, wit_prg, network = b32.witness_from_address( address.strip().encode("ascii")) assert addr == b32.address_from_witness(wit_ver, wit_prg, network) script_pub_key: List[Command] = [op_int(wit_ver), wit_prg] assert serialize(script_pub_key).hex() == hexscript
def test_invalid_address_enc() -> None: "Test whether address encoding fails on invalid input." invalid_address_enc: List[Tuple[str, int, int, str]] = [ ("MAINNET", 0, 20, "'MAINNET'"), ("mainnet", 0, 21, "invalid size: "), ("mainnet", 17, 32, "invalid witness version: "), ("mainnet", 1, 1, "invalid size: "), ("mainnet", 16, 41, "invalid size: "), ] network, wit_ver, length, err_msg = invalid_address_enc[0] with pytest.raises(KeyError, match=err_msg): b32.address_from_witness(wit_ver, "00" * length, network) for network, wit_ver, length, err_msg in invalid_address_enc[1:]: with pytest.raises(BTClibValueError, match=err_msg): b32.address_from_witness(wit_ver, "00" * length, network)
def test_valid_address() -> None: "Test whether valid addresses decode to the correct output." valid_bc_addresses: List[Tuple[str, str]] = [ ( "BC1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KV8F3T4", "0014751e76e8199196d454941c45d1b3a323f1433bd6", ), ( "bc1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7k7grplx", "5128751e76e8199196d454941c45d1b3a323f1433bd6751e76e8199196d454941c45d1b3a323f1433bd6", ), ("BC1SW50QA3JX3S", "6002751e"), ( "bc1zw508d6qejxtdg4y5r3zarvaryvg6kdaj", "5210751e76e8199196d454941c45d1b3a323", ), ( " bc1zw508d6qejxtdg4y5r3zarvaryvg6kdaj", # extra leading space "5210751e76e8199196d454941c45d1b3a323", ), ] valid_tb_addresses: List[Tuple[str, str]] = [ ( "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7", "00201863143c14c5166804bd19203356da136c985678cd4d27a1b8c6329604903262", ), ( "tb1qqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesrxh6hy", "0020000000c4a5cad46221b2a187905e5266362b99d5e91c6ce24d165dab93e86433", ), ] for address, hexscript in valid_bc_addresses + valid_tb_addresses: addr = b32.address_from_witness(*b32.witness_from_address(address)) assert address.lower().strip() == addr wit_ver, wit_prg, network = b32.witness_from_address( address.strip().encode("ascii")) assert addr == b32.address_from_witness(wit_ver, wit_prg, network) script_pub_key: List[Command] = [op_int(wit_ver), wit_prg] assert serialize(script_pub_key).hex() == hexscript
def test_p2wsh() -> None: # https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki pub = "02 79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798" script_pub_key: List[Command] = [pub, "OP_CHECKSIG"] witness_script_bytes = serialize(script_pub_key) addr = "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7" assert addr == b32.p2wsh(witness_script_bytes, "testnet") _, wit_prg, _ = b32.witness_from_address(addr) assert wit_prg == sha256(witness_script_bytes) addr = "bc1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qccfmv3" assert addr == b32.p2wsh(witness_script_bytes) _, wit_prg, _ = b32.witness_from_address(addr) assert wit_prg == sha256(witness_script_bytes) err_msg = "invalid size: " with pytest.raises(BTClibValueError, match=err_msg): b32.address_from_witness(0, witness_script_bytes)