def test_p2sh(self): script_type = "p2sh" # self-consistency pubkey = "02" "cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaf" pubkey_hash = hash160(pubkey) redeem_script = scriptPubKey_from_payload("p2pkh", pubkey_hash) payload = hash160(redeem_script) script = encode(["OP_HASH160", payload, "OP_EQUAL"]) # straight to the scriptPubKey scriptPubKey = p2sh(redeem_script) self.assertEqual(scriptPubKey.hex(), script.hex()) # to the scriptPubKey in two steps (through payload) scriptPubKey = scriptPubKey_from_payload(script_type, payload) self.assertEqual(scriptPubKey.hex(), script.hex()) # back from the scriptPubKey to the payload script_type2, payload2, m2 = payload_from_scriptPubKey(scriptPubKey) self.assertEqual(script_type, script_type2) self.assertEqual(0, m2) self.assertEqual(payload.hex(), payload2.hex()) script_type2, payload2, m2 = payload_from_scriptPubKey(script) self.assertEqual(script_type, script_type2) self.assertEqual(0, m2) self.assertEqual(payload.hex(), payload2.hex()) # data -> payload is not invertible (hash functions) # address network = "mainnet" address = base58address.p2sh(decode(redeem_script), network) address2 = address_from_scriptPubKey(scriptPubKey, network) self.assertEqual(address, address2) prefix = NETWORKS[network]["p2sh"] address2 = b58address_from_h160(prefix, payload, network) self.assertEqual(address, address2) scriptPubKey2, network2 = scriptPubKey_from_address(address) self.assertEqual(scriptPubKey2, scriptPubKey) self.assertEqual(network2, network) # documented test case: https://learnmeabitcoin.com/guide/p2sh payload = "748284390f9e263a4b766a75d0633c50426eb875" script = "a914748284390f9e263a4b766a75d0633c50426eb87587" scriptPubKey = scriptPubKey_from_payload(script_type, payload) self.assertEqual(scriptPubKey.hex(), script) network = "mainnet" address = b"3CK4fEwbMP7heJarmU4eqA3sMbVJyEnU3V" address2 = address_from_scriptPubKey(scriptPubKey, network) self.assertEqual(address, address2) scriptPubKey2, network2 = scriptPubKey_from_address(address) self.assertEqual(scriptPubKey2, scriptPubKey) self.assertEqual(network2, network) # invalid size: 21 bytes instead of 20 self.assertRaises(ValueError, scriptPubKey_from_payload, "00" * 21, "p2sh")
def test_p2wsh() -> None: # self-consistency pubkey = "02 cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaf" pubkey_hash = hash160(pubkey) redeem_script = scriptPubKey_from_payload("p2pkh", pubkey_hash) payload = sha256(redeem_script) scriptPubKey = script.encode([0, payload]) assert scriptPubKey == p2wsh(script.decode(redeem_script)) # to the scriptPubKey in two steps (through payload) script_type = "p2wsh" assert scriptPubKey == scriptPubKey_from_payload(script_type, payload) # back from the scriptPubKey to the payload assert (script_type, payload, 0) == payload_from_scriptPubKey(scriptPubKey) # bech32 address network = "mainnet" address = bech32address.p2wsh(redeem_script, network) assert address == address_from_scriptPubKey(scriptPubKey, network) wit_ver = 0 assert address == b32address_from_witness(wit_ver, payload, network) # back from the address to the scriptPubKey assert (scriptPubKey, network) == scriptPubKey_from_address(address) # p2sh-wrapped base58 address address = base58address.p2wsh_p2sh(redeem_script, network) assert address == b58address_from_witness(payload, network)
def test_p2pkh(self): script_type = 'p2pkh' # self-consistency pubkey = "04cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4" payload = hash160(pubkey) script = encode(['OP_DUP', 'OP_HASH160', payload, 'OP_EQUALVERIFY', 'OP_CHECKSIG']) # straight to the scriptPubKey scriptPubKey = p2pkh(pubkey) self.assertEqual(scriptPubKey.hex(), script.hex()) # to the scriptPubKey in two steps (through payload) scriptPubKey = scriptPubKey_from_payload(script_type, payload) self.assertEqual(scriptPubKey.hex(), script.hex()) # back from the scriptPubKey to the payload script_type2, payload2, m2 = payload_from_scriptPubKey(scriptPubKey) self.assertEqual(script_type, script_type2) self.assertEqual(0, m2) self.assertEqual(payload.hex(), payload2.hex()) script_type2, payload2, m2 = payload_from_scriptPubKey(script) self.assertEqual(script_type, script_type2) self.assertEqual(0, m2) self.assertEqual(payload.hex(), payload2.hex()) # data -> payload is not invertible (hash functions) # address network = 'mainnet' address = base58address.p2pkh(pubkey, network) address2 = address_from_scriptPubKey(scriptPubKey, network) self.assertEqual(address, address2) prefix = p2pkh_prefix_from_network(network) address2 = b58address_from_h160(prefix, payload) self.assertEqual(address, address2) scriptPubKey2, network2 = scriptPubKey_from_address(address) self.assertEqual(scriptPubKey2, scriptPubKey) self.assertEqual(network2, network) # documented test case: https://learnmeabitcoin.com/guide/p2pkh payload = "12ab8dc588ca9d5787dde7eb29569da63c3a238c" script = "76a91412ab8dc588ca9d5787dde7eb29569da63c3a238c88ac" scriptPubKey = scriptPubKey_from_payload(script_type, payload) self.assertEqual(scriptPubKey.hex(), script) network = 'mainnet' address = b"12higDjoCCNXSA95xZMWUdPvXNmkAduhWv" address2 = address_from_scriptPubKey(scriptPubKey, network) self.assertEqual(address, address2) scriptPubKey2, network2 = scriptPubKey_from_address(address) self.assertEqual(scriptPubKey2, scriptPubKey) self.assertEqual(network2, network) # Invalid size: 11 bytes instead of 20 self.assertRaises( ValueError, scriptPubKey_from_payload, "00" * 11, 'p2pkh')
def test_p2ms_2(self): pubkey1 = ( "04" "cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaf" "f7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4" ) pubkey2 = ( "04" "61cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d765" "19aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af" ) pubkey3 = ( "04" "79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798" "483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8" ) pubkeys = [pubkey1, pubkey2, pubkey3] m = 1 n = len(pubkeys) script = [m] + pubkeys + [n, "OP_CHECKMULTISIG"] payload_from_scriptPubKey(script) scriptPubKey_from_payload("p2ms", pubkeys, m) # Invalid list of Octets for p2sh script self.assertRaises(ValueError, scriptPubKey_from_payload, "p2sh", pubkeys, 0) # scriptPubKey_from_payload('p2sh', pubkeys, 0) # Invalid number of keys (0) in m-of-n multisignature script = [1, 3, "OP_CHECKMULTISIG"] self.assertRaises(ValueError, payload_from_scriptPubKey, script) # payload_from_scriptPubKey(script) # Keys (2) / n (3) mismatch in m-of-n multisignature script = [1, pubkey1, pubkey2, 3, "OP_CHECKMULTISIG"] self.assertRaises(ValueError, payload_from_scriptPubKey, script) # payload_from_scriptPubKey(script) # Impossible 3-of-2 multisignature script = [3, pubkey1, pubkey2, 2, "OP_CHECKMULTISIG"] self.assertRaises(ValueError, payload_from_scriptPubKey, script) # payload_from_scriptPubKey(script) # Invalid m (0) in 0-of-2 multisignature script = [0, pubkey1, pubkey2, 2, "OP_CHECKMULTISIG"] self.assertRaises(ValueError, payload_from_scriptPubKey, script) # payload_from_scriptPubKey(script) # 133-th byte in 1-of-3 multisignature payload is 0x40, # it should have been 0x41 script = [1, pubkey1, pubkey2, pubkey3, 3, "OP_CHECKMULTISIG"] bscript = encode(script) script = bscript[:133] + b"\x40" + bscript[134:] self.assertRaises(ValueError, payload_from_scriptPubKey, script)
def test_nulldata() -> None: # self-consistency string = "time-stamped data" payload = string.encode() scriptPubKey = script.encode(["OP_RETURN", payload]) assert scriptPubKey == nulldata(string) # to the scriptPubKey in two steps (through payload) script_type = "nulldata" assert scriptPubKey == scriptPubKey_from_payload(script_type, payload) # back from the scriptPubKey to the payload assert (script_type, payload, 0) == payload_from_scriptPubKey(scriptPubKey) # data -> payload in this case is invertible (no hash functions) assert payload.decode() == string err_msg = "no address for null data script" with pytest.raises(ValueError, match=err_msg): address_from_scriptPubKey(scriptPubKey) # documented test cases: https://learnmeabitcoin.com/guide/nulldata string = "hello world" payload = string.encode() assert payload.hex() == "68656c6c6f20776f726c64" # pylint: disable=no-member scriptPubKey = b"\x6a\x0b" + payload assert scriptPubKey == nulldata(string) assert scriptPubKey == scriptPubKey_from_payload(script_type, payload) assert (script_type, payload, 0) == payload_from_scriptPubKey(scriptPubKey) # documented test cases: https://learnmeabitcoin.com/guide/nulldata string = "charley loves heidi" payload = string.encode() assert (payload.hex() # pylint: disable=no-member == "636861726c6579206c6f766573206865696469") scriptPubKey = b"\x6a\x13" + payload assert scriptPubKey == nulldata(string) assert scriptPubKey == scriptPubKey_from_payload(script_type, payload) assert (script_type, payload, 0) == payload_from_scriptPubKey(scriptPubKey) # documented test cases: https://learnmeabitcoin.com/guide/nulldata string = "家族も友達もみんなが笑顔の毎日がほしい" payload = string.encode() assert ( payload.hex() # pylint: disable=no-member == "e5aeb6e6978fe38282e58f8be98194e38282e381bfe38293e381aae3818ce7ac91e9a194e381aee6af8ee697a5e3818ce381bbe38197e38184" ) scriptPubKey = b"\x6a\x39" + payload assert scriptPubKey == nulldata(string) assert scriptPubKey == scriptPubKey_from_payload(script_type, payload) assert (script_type, payload, 0) == payload_from_scriptPubKey(scriptPubKey)
def test_p2pk() -> None: # self-consistency pubkey = "02 cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaf" scriptPubKey = script.encode([pubkey, "OP_CHECKSIG"]) assert scriptPubKey == p2pk(pubkey) # to the scriptPubKey in two steps (through payload) script_type = "p2pk" assert scriptPubKey == scriptPubKey_from_payload(script_type, pubkey) # back from the scriptPubKey to the payload assert (script_type, bytes.fromhex(pubkey), 0) == payload_from_scriptPubKey(scriptPubKey) err_msg = "no address for p2pk scriptPubKey" with pytest.raises(ValueError, match=err_msg): address_from_scriptPubKey(scriptPubKey) # documented test case: https://learnmeabitcoin.com/guide/p2pk pubkey = ( "04" "ae1a62fe09c5f51b13905f07f06b99a2f7159b2225f374cd378d71302fa28414" "e7aab37397f554a7df5f142c21c1b7303b8a0626f1baded5c72a704f7e6cd84c") scriptPubKey = "41" + pubkey + "ac" assert scriptPubKey == p2pk(pubkey).hex() # invalid size: 34 bytes instead of (33, 65) pubkey = ( # fmt: off "03" "ae1a62fe09c5f51b13905f07f06b99a2f7159b2225f374cd378d71302fa28414" "14") # fmt: on err_msg = "not a private or public key: " with pytest.raises(ValueError, match=err_msg): p2pk(pubkey)
def test_CLT(self): network = 'mainnet' vault_pubkeys = [b'\x00' * 33, b'\x11' * 33, b'\x22' * 33] recovery_pubkeys = [b'\x77' * 33, b'\x88' * 33, b'\x99' * 33] redeem_script = encode([ 'OP_IF', 2, *vault_pubkeys, 3, 'OP_CHECKMULTISIG', 'OP_ELSE', 500, 'OP_CHECKLOCKTIMEVERIFY', 'OP_DROP', 2, *recovery_pubkeys, 3, 'OP_CHECKMULTISIG', 'OP_ENDIF' ]) payload = sha256(redeem_script) script = "00207b5310339c6001f75614daa5083839fa54d46165f6c56025cc54d397a85a5708" scriptPubKey = p2wsh(redeem_script) self.assertEqual(scriptPubKey.hex(), script) scriptPubKey = scriptPubKey_from_payload('p2wsh', payload) self.assertEqual(scriptPubKey.hex(), script) address = b"bc1q0df3qvuuvqqlw4s5m2jsswpelf2dgct97mzkqfwv2nfe02z62uyq7n4zjj" address2 = address_from_scriptPubKey(scriptPubKey, network) self.assertEqual(address, address2) address2 = bech32address.p2wsh(redeem_script, network) self.assertEqual(address, address2) address2 = b32address_from_witness(0, payload, network) self.assertEqual(address, address2)
def test_p2ms_3(self): # mixed compressed / uncompressed public keys pubkey1 = ( "04" "cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaf" "f7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4" ) pubkey2 = ( "03" "61cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d765" ) pubkey3 = ( "02" "79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798" ) pubkeys = [ bytes.fromhex(pubkey1), bytes.fromhex(pubkey2), bytes.fromhex(pubkey3), ] m = 1 n = len(pubkeys) script = scriptPubKey_from_payload("p2ms", pubkeys, m) pubkeys.sort() exp_script = encode([m] + pubkeys + [n, "OP_CHECKMULTISIG"]) self.assertEqual(script.hex(), exp_script.hex()) script_type, payload, m2 = payload_from_scriptPubKey(script) self.assertEqual(script_type, "p2ms") self.assertEqual(m, m2) self.assertEqual(pubkeys, payload)
def test_CLT() -> None: network = "mainnet" fed_pubkeys = [b"\x00" * 33, b"\x11" * 33, b"\x22" * 33] rec_pubkeys = [b"\x77" * 33, b"\x88" * 33, b"\x99" * 33] # fmt: off redeem_script = script.encode([ "OP_IF", 2, *fed_pubkeys, 3, "OP_CHECKMULTISIG", # noqa E131 "OP_ELSE", 500, "OP_CHECKLOCKTIMEVERIFY", "OP_DROP", # noqa E131 2, *rec_pubkeys, 3, "OP_CHECKMULTISIG", # noqa E131 "OP_ENDIF", ]) # fmt: on payload = sha256(redeem_script) scriptPubKey = ( "00207b5310339c6001f75614daa5083839fa54d46165f6c56025cc54d397a85a5708") assert scriptPubKey == p2wsh(redeem_script).hex() assert scriptPubKey == scriptPubKey_from_payload("p2wsh", payload).hex() address = b"bc1q0df3qvuuvqqlw4s5m2jsswpelf2dgct97mzkqfwv2nfe02z62uyq7n4zjj" assert address == address_from_scriptPubKey(scriptPubKey, network) assert address == b32address_from_witness(0, payload, network)
def test_p2ms_p2sh() -> None: "BIP67 test vectors https://en.bitcoin.it/wiki/BIP_0067" data_folder = path.join(path.dirname(__file__), "test_data") filename = path.join(data_folder, "bip67_test_vectors.json") with open(filename, "r") as f: # json.dump(test_vectors, f, indent=4) test_vectors = json.load(f) m = 2 for i in test_vectors: keys, address = test_vectors[i] errmsg = f"Test vector #{int(i)}" scriptPubKey = p2ms(keys, m) addr = base58address.p2sh(scriptPubKey) assert addr.decode() == address, errmsg scriptPubKey = scriptPubKey_from_payload("p2ms", keys, m) addr = base58address.p2sh(scriptPubKey) assert addr.decode() == address, errmsg script_type, payload, m2 = payload_from_scriptPubKey(scriptPubKey) assert script_type == "p2ms", errmsg for key, k in zip(sorted(keys), payload): assert key == k.hex(), errmsg assert m2 == m, errmsg
def test_p2wsh(self): script_type = "p2wsh" # self-consistency pubkey = "02" "cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaf" pubkey_hash = hash160(pubkey) redeem_script = scriptPubKey_from_payload("p2pkh", pubkey_hash) payload = sha256(redeem_script) script = encode([0, payload]) # straight to the scriptPubKey scriptPubKey = p2wsh(decode(redeem_script)) self.assertEqual(scriptPubKey.hex(), script.hex()) # to the scriptPubKey in two steps (through payload) scriptPubKey = scriptPubKey_from_payload(script_type, payload) self.assertEqual(scriptPubKey.hex(), script.hex()) # back from the scriptPubKey to the payload script_type2, payload2, m2 = payload_from_scriptPubKey(scriptPubKey) self.assertEqual(script_type, script_type2) self.assertEqual(0, m2) self.assertEqual(payload.hex(), payload2.hex()) script_type2, payload2, m2 = payload_from_scriptPubKey(script) self.assertEqual(script_type, script_type2) self.assertEqual(0, m2) self.assertEqual(payload.hex(), payload2.hex()) # data -> payload is not invertible (hash functions) # bech32 address network = "mainnet" address = bech32address.p2wsh(redeem_script, network) address2 = address_from_scriptPubKey(scriptPubKey, network) self.assertEqual(address, address2) address2 = b32address_from_witness(0, payload, network) self.assertEqual(address, address2) scriptPubKey2, network2 = scriptPubKey_from_address(address) self.assertEqual(scriptPubKey2, scriptPubKey) self.assertEqual(network2, network) # p2sh-wrapped base58 address address = base58address.p2wsh_p2sh(redeem_script, network) address2 = b58address_from_witness(payload, network) self.assertEqual(address, address2)
def test_p2pkh() -> None: # self-consistency pubkey = ( "04 " "cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaf" "f7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4") payload = hash160(pubkey) scriptPubKey = script.encode( ["OP_DUP", "OP_HASH160", payload, "OP_EQUALVERIFY", "OP_CHECKSIG"]) assert scriptPubKey == p2pkh(pubkey) # to the scriptPubKey in two steps (through payload) script_type = "p2pkh" assert scriptPubKey == scriptPubKey_from_payload(script_type, payload) # back from the scriptPubKey to the payload assert (script_type, payload, 0) == payload_from_scriptPubKey(scriptPubKey) # base58 address network = "mainnet" address = base58address.p2pkh(pubkey, network) assert address == address_from_scriptPubKey(scriptPubKey, network) prefix = NETWORKS[network]["p2pkh"] assert address == b58address_from_h160(prefix, payload, network) # back from the address to the scriptPubKey assert (scriptPubKey, network) == scriptPubKey_from_address(address) # documented test case: https://learnmeabitcoin.com/guide/p2pkh payload = "12ab8dc588ca9d5787dde7eb29569da63c3a238c" scriptPubKey = "76a914" + payload + "88ac" assert scriptPubKey == scriptPubKey_from_payload(script_type, payload).hex() address = b"12higDjoCCNXSA95xZMWUdPvXNmkAduhWv" assert address == address_from_scriptPubKey(scriptPubKey, network) assert (bytes.fromhex(scriptPubKey), network) == scriptPubKey_from_address(address) # invalid size: 11 bytes instead of 20 err_msg = "invalid size: " with pytest.raises(ValueError, match=err_msg): scriptPubKey_from_payload(script_type, "00" * 11)
def test_p2ms_p2sh(self): test_vectors = [ [0, ['022df8750480ad5b26950b25c7ba79d3e37d75f640f8e5d9bcd5b150a0f85014da', '03e3818b65bcc73a7d64064106a859cc1a5a728c4345ff0b641209fba0d90de6e9', '021f2f6e1e50cb6a953935c3601284925decd3fd21bc445712576873fb8c6ebc18', ], b'3Q4sF6tv9wsdqu2NtARzNCpQgwifm2rAba' ], [1, ['02ff12471208c14bd580709cb2358d98975247d8765f92bc25eab3b2763ed605f8', '02fe6f0a5a297eb38c391581c4413e084773ea23954d93f7753db7dc0adc188b2f', ], b'39bgKC7RFbpoCRbtD5KEdkYKtNyhpsNa3Z' ], [2, ['02632b12f4ac5b1d1b72b2a3b508c19172de44f6f46bcee50ba33f3f9291e47ed0', '027735a29bae7780a9755fae7a1c4374c656ac6a69ea9f3697fda61bb99a4f3e77', '02e2cc6bd5f45edd43bebe7cb9b675f0ce9ed3efe613b177588290ad188d11b404', ], b'3CKHTjBKxCARLzwABMu9yD85kvtm7WnMfH' ], [3, ['030000000000000000000000000000000000004141414141414141414141414141', '020000000000000000000000000000000000004141414141414141414141414141', '020000000000000000000000000000000000004141414141414141414141414140', '030000000000000000000000000000000000004141414141414141414141414140', ], b'32V85igBri9zcfBRVupVvwK18NFtS37FuD' ], [4, ['022df8750480ad5b26950b25c7ba79d3e37d75f640f8e5d9bcd5b150a0f85014da', '03e3818b65bcc73a7d64064106a859cc1a5a728c4345ff0b641209fba0d90de6e9', '021f2f6e1e50cb6a953935c3601284925decd3fd21bc445712576873fb8c6ebc18', ], b'3Q4sF6tv9wsdqu2NtARzNCpQgwifm2rAba' ], ] m = 2 for i, keys, address in test_vectors: errmsg = f"Test vector #{int(i)}" script = p2ms(keys, m) addr = base58address.p2sh(script) self.assertEqual(addr, address, errmsg) script = scriptPubKey_from_payload('p2ms', keys, m) addr = base58address.p2sh(script) self.assertEqual(addr, address, errmsg) script_type, payload, m2 = payload_from_scriptPubKey(script) self.assertEqual(script_type, 'p2ms', errmsg) for key, k in zip(sorted(keys), payload): self.assertEqual(key, k.hex(), errmsg) self.assertEqual(m2, m, errmsg)
def test_p2ms_2() -> None: pubkey1 = "04 cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaf f7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4" pubkey2 = "04 61cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d765 19aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af" pubkey3 = "04 79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798 483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8" pubkeys = [pubkey1, pubkey2, pubkey3] m = 1 n = len(pubkeys) scriptPubKey = [m] + pubkeys + [n, "OP_CHECKMULTISIG"] payload_from_scriptPubKey(scriptPubKey) scriptPubKey_from_payload("p2ms", pubkeys, m) err_msg = "invalid list of Octets for p2sh scriptPubKey" with pytest.raises(ValueError, match=err_msg): scriptPubKey_from_payload("p2sh", pubkeys, 0) err_msg = "invalid number of pubkeys in " scriptPubKey = [1, 3, "OP_CHECKMULTISIG"] with pytest.raises(ValueError, match=err_msg): payload_from_scriptPubKey(scriptPubKey) err_msg = "wrong number of pubkeys in " scriptPubKey = [1, pubkey1, pubkey2, 3, "OP_CHECKMULTISIG"] with pytest.raises(ValueError, match=err_msg): payload_from_scriptPubKey(scriptPubKey) err_msg = "invalid number of pubkeys in " scriptPubKey = [3, pubkey1, pubkey2, 2, "OP_CHECKMULTISIG"] with pytest.raises(ValueError, match=err_msg): payload_from_scriptPubKey(scriptPubKey) err_msg = "invalid m in m-of-n multisignature: " scriptPubKey = [0, pubkey1, pubkey2, 2, "OP_CHECKMULTISIG"] with pytest.raises(ValueError, match=err_msg): payload_from_scriptPubKey(scriptPubKey) scriptPubKey = script.encode( [1, pubkey1, pubkey2, pubkey3, 3, "OP_CHECKMULTISIG"]) scriptPubKey = scriptPubKey[:133] + b"\x40" + scriptPubKey[134:] err_msg = "wrong number of pubkeys in " with pytest.raises(ValueError, match=err_msg): payload_from_scriptPubKey(scriptPubKey)
def test_p2sh() -> None: # self-consistency pubkey = "02 cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaf" pubkey_hash = hash160(pubkey) redeem_script = scriptPubKey_from_payload("p2pkh", pubkey_hash) payload = hash160(redeem_script) scriptPubKey = script.encode(["OP_HASH160", payload, "OP_EQUAL"]) assert scriptPubKey == p2sh(redeem_script) # to the scriptPubKey in two steps (through payload) script_type = "p2sh" assert scriptPubKey == scriptPubKey_from_payload(script_type, payload) # back from the scriptPubKey to the payload assert (script_type, payload, 0) == payload_from_scriptPubKey(scriptPubKey) # base58 address network = "mainnet" address = base58address.p2sh(script.decode(redeem_script), network) assert address == address_from_scriptPubKey(scriptPubKey, network) prefix = NETWORKS[network]["p2sh"] assert address == b58address_from_h160(prefix, payload, network) # back from the address to the scriptPubKey assert (scriptPubKey, network) == scriptPubKey_from_address(address) # documented test case: https://learnmeabitcoin.com/guide/p2sh payload = "748284390f9e263a4b766a75d0633c50426eb875" scriptPubKey = "a914" + payload + "87" assert scriptPubKey == scriptPubKey_from_payload(script_type, payload).hex() address = b"3CK4fEwbMP7heJarmU4eqA3sMbVJyEnU3V" assert address == address_from_scriptPubKey(scriptPubKey, network) assert (bytes.fromhex(scriptPubKey), network) == scriptPubKey_from_address(address) # invalid size: 21 bytes instead of 20 err_msg = "invalid size: " with pytest.raises(ValueError, match=err_msg): scriptPubKey_from_payload(script_type, "00" * 21)
def test_p2pk(self): script_type = "p2pk" # self-consistency pubkey = "02" "cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaf" script = encode([pubkey, "OP_CHECKSIG"]) # straight to the scriptPubKey scriptPubKey = p2pk(pubkey) self.assertEqual(scriptPubKey.hex(), script.hex()) # to the scriptPubKey in two steps (through payload) scriptPubKey = scriptPubKey_from_payload(script_type, pubkey) self.assertEqual(scriptPubKey.hex(), script.hex()) # back from the scriptPubKey to the payload script_type2, payload2, m2 = payload_from_scriptPubKey(scriptPubKey) self.assertEqual(script_type, script_type2) self.assertEqual(0, m2) self.assertEqual(bytes.fromhex(pubkey).hex(), payload2.hex()) script_type2, payload2, m2 = payload_from_scriptPubKey(script) self.assertEqual(script_type, script_type2) self.assertEqual(0, m2) self.assertEqual(bytes.fromhex(pubkey).hex(), payload2.hex()) # data -> payload in this case is invertible (no hash functions) # No address for p2pk script self.assertRaises(ValueError, address_from_scriptPubKey, scriptPubKey) # address_from_scriptPubKey(scriptPubKey) # documented test case: https://learnmeabitcoin.com/guide/p2pk pubkey = ( "04" "ae1a62fe09c5f51b13905f07f06b99a2f7159b2225f374cd378d71302fa28414" "e7aab37397f554a7df5f142c21c1b7303b8a0626f1baded5c72a704f7e6cd84c" ) script = ( "4104" "ae1a62fe09c5f51b13905f07f06b99a2f7159b2225f374cd378d71302fa28414" "e7aab37397f554a7df5f142c21c1b7303b8a0626f1baded5c72a704f7e6cd84c" "ac" ) scriptPubKey = p2pk(pubkey) self.assertEqual(scriptPubKey.hex(), script) # Invalid size: 34 bytes instead of (33, 65) pubkey = ( "03" "ae1a62fe09c5f51b13905f07f06b99a2f7159b2225f374cd378d71302fa28414" "14" ) self.assertRaises(ValueError, p2pk, pubkey)
def test_exceptions() -> None: # invalid size: 11 bytes instead of 20 err_msg = "invalid size: " with pytest.raises(ValueError, match=err_msg): scriptPubKey_from_payload("p2wpkh", "00" * 11) # invalid size: 33 bytes instead of 32 with pytest.raises(ValueError, match=err_msg): scriptPubKey_from_payload("p2wsh", "00" * 33) err_msg = "unknown scriptPubKey type: " with pytest.raises(ValueError, match=err_msg): scriptPubKey_from_payload("p2unkn", "00" * 32) err_msg = "unknown scriptPubKey: " with pytest.raises(ValueError, match=err_msg): scriptPubKey = [16, 20 * b"\x00"] address_from_scriptPubKey(scriptPubKey) # Unhandled witness version (16) err_msg = "unmanaged witness version: " address = b32address_from_witness(16, 20 * b"\x00") with pytest.raises(ValueError, match=err_msg): scriptPubKey_from_address(address)
def test_nulldata3() -> None: err_msg = "invalid nulldata script lenght: " with pytest.raises(ValueError, match=err_msg): payload = "00" * 81 scriptPubKey_from_payload("nulldata", payload) # wrong data lenght: 32 in 35-bytes nulldata script; # it should have been 33 scriptPubKey = script.encode(["OP_RETURN", b"\x00" * 33]) scriptPubKey = scriptPubKey[:1] + b"\x20" + scriptPubKey[2:] err_msg = "wrong data lenght: " with pytest.raises(ValueError, match=err_msg): payload_from_scriptPubKey(scriptPubKey) # wrong data lenght: 32 in 83-bytes nulldata script; # it should have been 80 scriptPubKey = script.encode(["OP_RETURN", b"\x00" * 80]) scriptPubKey = scriptPubKey[:2] + b"\x20" + scriptPubKey[3:] with pytest.raises(ValueError, match=err_msg): payload_from_scriptPubKey(scriptPubKey) # missing OP_PUSHDATA1 (0x4c) in 83-bytes nulldata script, # got 0x20 instead scriptPubKey = script.encode(["OP_RETURN", b"\x00" * 80]) scriptPubKey = scriptPubKey[:1] + b"\x20" + scriptPubKey[2:] err_msg = "missing OP_PUSHDATA1 " with pytest.raises(ValueError, match=err_msg): payload_from_scriptPubKey(scriptPubKey) assert len(script.encode(["OP_RETURN", b"\x00" * 75])) == 77 assert len(script.encode(["OP_RETURN", b"\x00" * 76])) == 79 scriptPubKey = script.encode(["OP_RETURN", b"\x00" * 76])[:-1] err_msg = "invalid 78 bytes nulldata script length" with pytest.raises(ValueError, match=err_msg): payload_from_scriptPubKey(scriptPubKey)
def test_nulldata2() -> None: script_type = "nulldata" # max length case byte = b"\x00" for length in (0, 1, 16, 17, 74, 75, 76, 77, 78, 79, 80): payload = byte * length scriptPubKey = script.encode(["OP_RETURN", payload]) assert scriptPubKey == scriptPubKey_from_payload(script_type, payload) # back from the scriptPubKey to the payload assert (script_type, payload, 0) == payload_from_scriptPubKey(scriptPubKey) assert (script_type, payload, 0) == payload_from_scriptPubKey(script.decode(scriptPubKey))
def test_p2ms_3() -> None: # mixed compressed / uncompressed public keys pubkey1 = "04 cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaf f7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4" pubkey2 = "03 61cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d765" pubkey3 = "02 79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798" pubkeys = [ bytes.fromhex(pubkey1), bytes.fromhex(pubkey2), bytes.fromhex(pubkey3), ] m = 1 n = len(pubkeys) scriptPubKey = scriptPubKey_from_payload("p2ms", pubkeys, m) pubkeys.sort() exp_script = script.encode([m] + pubkeys + [n, "OP_CHECKMULTISIG"]) assert scriptPubKey.hex() == exp_script.hex() script_type, payload, m2 = payload_from_scriptPubKey(scriptPubKey) assert script_type == "p2ms" assert m == m2 assert pubkeys == payload
def test_CLT(): network = "mainnet" vault_pubkeys = [b"\x00" * 33, b"\x11" * 33, b"\x22" * 33] recovery_pubkeys = [b"\x77" * 33, b"\x88" * 33, b"\x99" * 33] redeem_script = encode( [ "OP_IF", 2, *vault_pubkeys, 3, "OP_CHECKMULTISIG", "OP_ELSE", 500, "OP_CHECKLOCKTIMEVERIFY", "OP_DROP", 2, *recovery_pubkeys, 3, "OP_CHECKMULTISIG", "OP_ENDIF", ] ) payload = sha256(redeem_script) script = "00207b5310339c6001f75614daa5083839fa54d46165f6c56025cc54d397a85a5708" scriptPubKey = p2wsh(redeem_script) assert scriptPubKey.hex() == script scriptPubKey = scriptPubKey_from_payload("p2wsh", payload) assert scriptPubKey.hex() == script address = ( "bc1q0df3qvuuvqqlw4s5m2jsswpelf2dgct97mzkqfwv2nfe02z62uyq7n4zjj" ).encode() address2 = address_from_scriptPubKey(scriptPubKey, network) assert address == address2 assert address == address2 address2 = b32address_from_witness(0, payload, network) assert address == address2
def test_nulldata2(self): script_type = "nulldata" # max length case byte = b"\x00" for length in (0, 1, 16, 17, 74, 75, 80): payload = byte * length script = encode(["OP_RETURN", payload]) scriptPubKey = scriptPubKey_from_payload(script_type, payload) self.assertEqual(scriptPubKey.hex(), script.hex()) # back from the scriptPubKey to the payload script_type2, payload2, m2 = payload_from_scriptPubKey(scriptPubKey) self.assertEqual(script_type, script_type2) self.assertEqual(0, m2) self.assertEqual(payload.hex(), payload2.hex()) script_type2, payload2, m2 = payload_from_scriptPubKey(decode(script)) self.assertEqual(script_type, script_type2) self.assertEqual(0, m2) self.assertEqual(payload.hex(), payload2.hex())
def test_p2ms(self): script_type = "p2ms" # self-consistency pubkey1 = ( "04" "cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaf" "f7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4" ) pubkey2 = ( "04" "61cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d765" "19aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af" ) pubkeys = [bytes.fromhex(pubkey1), bytes.fromhex(pubkey2)] m = 1 # straight to the scriptPubKey scriptPubKey = p2ms(pubkeys, m) n = len(pubkeys) script = encode([m] + sorted(pubkeys) + [n, "OP_CHECKMULTISIG"]) self.assertEqual(scriptPubKey.hex(), script.hex()) # to the scriptPubKey in two steps (through payload) scriptPubKey = scriptPubKey_from_payload(script_type, pubkeys, m) self.assertEqual(scriptPubKey.hex(), script.hex()) # back from the scriptPubKey to the payload script_type2, payload2, m2 = payload_from_scriptPubKey(scriptPubKey) self.assertEqual(script_type, script_type2) self.assertEqual(m, m2) self.assertEqual(sorted(pubkeys), payload2) script_type2, payload2, m2 = payload_from_scriptPubKey(script) self.assertEqual(script_type, script_type2) self.assertEqual(m, m2) self.assertEqual(sorted(pubkeys), payload2) # data -> payload in this case is invertible (no hash functions) # No address for p2ms script self.assertRaises(ValueError, address_from_scriptPubKey, scriptPubKey) # address_from_scriptPubKey(scriptPubKey) # documented test case: https://learnmeabitcoin.com/guide/p2ms pubkey1 = ( "04" "cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaf" "f7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4" ) pubkey2 = ( "04" "61cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d765" "19aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af" ) pubkeys = [bytes.fromhex(pubkey1), bytes.fromhex(pubkey2)] m = 1 n = 2 script = ( "51" # OP_1 "41" # canonical 65-bytes push "04" "cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaf" "f7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4" "41" # canonical 65-bytes push "04" "61cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d765" "19aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af" "52" # OP_2 "ae" # OP_CHECKMULTISIG ) scriptPubKey = p2ms(pubkeys, 1, lexicographic_sort=False) self.assertEqual(scriptPubKey.hex(), script) # Impossible m>n 3-of-2 multisignature self.assertRaises(ValueError, p2ms, pubkeys, 3) # p2ms(pubkeys, 3) # Invalid m (0) for p2ms script self.assertRaises(ValueError, p2ms, pubkeys, 0) # p2ms(pubkeys, 0) # Invalid size: 66 bytes instead of 65 self.assertRaises(ValueError, p2ms, [pubkey1 + "00", pubkey2], 1) # p2ms([pubkey1 + "00", pubkey2], 1) # Invalid n (17) in 3-of-17 multisignature self.assertRaises(ValueError, p2ms, [pubkey1] * 17, 3) # p2ms([pubkey1]*17, 3) # Invalid key length (66) in p2ms badpubkeys = sorted(pubkeys) badpubkeys[0] = badpubkeys[0] + b"\x00" self.assertRaises( ValueError, scriptPubKey_from_payload, script_type, badpubkeys, m ) # scriptPubKey_from_payload(script_type, badpubkeys, m) # Invalid key length (66) in p2ms script = encode([m] + sorted(badpubkeys) + [n, "OP_CHECKMULTISIG"]) self.assertRaises(ValueError, payload_from_scriptPubKey, script) # payload_from_scriptPubKey(script) # Invalid key in p2ms script = encode([m] + [0, pubkeys[1]] + [n, "OP_CHECKMULTISIG"]) self.assertRaises(ValueError, payload_from_scriptPubKey, script) # payload_from_scriptPubKey(script) # Invalid m (0) for p2ms script self.assertRaises( ValueError, scriptPubKey_from_payload, script_type, pubkeys, 17 )
def test_p2ms() -> None: script_type = "p2ms" # self-consistency pubkey1 = ( "04" "cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaf" "f7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4") pubkey2 = ( "04" "61cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d765" "19aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af") pubkeys = [bytes.fromhex(pubkey1), bytes.fromhex(pubkey2)] m = 1 # straight to the scriptPubKey payload = sorted(pubkeys) n = len(pubkeys) scriptPubKey = script.encode([m] + payload + [n, "OP_CHECKMULTISIG"]) assert scriptPubKey == p2ms(pubkeys, m) # to the scriptPubKey in two steps (through payload) assert scriptPubKey == scriptPubKey_from_payload(script_type, pubkeys, m) # back from the scriptPubKey to the payload assert (script_type, payload, m) == payload_from_scriptPubKey(scriptPubKey) err_msg = "no address for p2ms scriptPubKey" with pytest.raises(ValueError, match=err_msg): address_from_scriptPubKey(scriptPubKey) # documented test case: https://learnmeabitcoin.com/guide/p2ms pubkeys = [bytes.fromhex(pubkey1), bytes.fromhex(pubkey2)] m = 1 n = 2 scriptPubKey = ( # fmt: off "51" # OP_1 "41" # canonical 65-bytes push + pubkey1 + "41" # noqa E148 # canonical 65-bytes push + pubkey2 + "52" # noqa E148 # OP_2 "ae" # OP_CHECKMULTISIG ) # fmt: on assert scriptPubKey == p2ms(pubkeys, 1, lexicographic_sort=False).hex() err_msg = "number-of-pubkeys < m in " with pytest.raises(ValueError, match=err_msg): p2ms(pubkeys, 3) err_msg = "invalid m for p2ms scriptPubKey: " with pytest.raises(ValueError, match=err_msg): p2ms(pubkeys, 0) err_msg = "not a private or public key: " with pytest.raises(ValueError, match=err_msg): p2ms([pubkey1 + "00", pubkey2], 1) err_msg = "too many pubkeys in m-of-n multisignature: " with pytest.raises(ValueError, match=err_msg): p2ms([pubkey1] * 17, 3) err_msg = "invalid size: " badpubkeys = sorted(pubkeys) badpubkeys[0] = badpubkeys[0] + b"\x00" with pytest.raises(ValueError, match=err_msg): scriptPubKey_from_payload(script_type, badpubkeys, m) scriptPubKey = script.encode([m] + sorted(badpubkeys) + [n, "OP_CHECKMULTISIG"]) with pytest.raises(ValueError, match=err_msg): payload_from_scriptPubKey(scriptPubKey) err_msg = "invalid key in p2ms" scriptPubKey = script.encode([m] + [0, pubkeys[1]] + [n, "OP_CHECKMULTISIG"]) with pytest.raises(ValueError, match=err_msg): payload_from_scriptPubKey(scriptPubKey) err_msg = "invalid m in m-of-n multisignature: " with pytest.raises(ValueError, match=err_msg): scriptPubKey_from_payload(script_type, pubkeys, 17)
def test_p2ms_p2sh(self): "BIP67 test vectors https://en.bitcoin.it/wiki/BIP_0067" test_vectors = { 0: [ [ ( "022df8750480ad5b26950b25c7ba79d3e37d75f640f8e5d9bcd5b1" "50a0f85014da" ), ( "03e3818b65bcc73a7d64064106a859cc1a5a728c4345ff0b641209" "fba0d90de6e9" ), ( "021f2f6e1e50cb6a953935c3601284925decd3fd21bc4457125768" "73fb8c6ebc18" ), ], b"3Q4sF6tv9wsdqu2NtARzNCpQgwifm2rAba", ], 1: [ [ ( "02ff12471208c14bd580709cb2358d98975247d8765f92bc25eab3" "b2763ed605f8" ), ( "02fe6f0a5a297eb38c391581c4413e084773ea23954d93f7753db7" "dc0adc188b2f" ), ], b"39bgKC7RFbpoCRbtD5KEdkYKtNyhpsNa3Z", ], 2: [ [ ( "02632b12f4ac5b1d1b72b2a3b508c19172de44f6f46bcee50ba33f" "3f9291e47ed0" ), ( "027735a29bae7780a9755fae7a1c4374c656ac6a69ea9f3697fda6" "1bb99a4f3e77" ), ( "02e2cc6bd5f45edd43bebe7cb9b675f0ce9ed3efe613b177588290" "ad188d11b404" ), ], b"3CKHTjBKxCARLzwABMu9yD85kvtm7WnMfH", ], 3: [ [ ( "030000000000000000000000000000000000004141414141414141" "414141414141" ), ( "020000000000000000000000000000000000004141414141414141" "414141414141" ), ( "020000000000000000000000000000000000004141414141414141" "414141414140" ), ( "030000000000000000000000000000000000004141414141414141" "414141414140" ), ], b"32V85igBri9zcfBRVupVvwK18NFtS37FuD", ], 4: [ [ ( "022df8750480ad5b26950b25c7ba79d3e37d75f640f8e5d9bcd5b1" "50a0f85014da" ), ( "03e3818b65bcc73a7d64064106a859cc1a5a728c4345ff0b641209" "fba0d90de6e9" ), ( "021f2f6e1e50cb6a953935c3601284925decd3fd21bc4457125768" "73fb8c6ebc18" ), ], b"3Q4sF6tv9wsdqu2NtARzNCpQgwifm2rAba", ], } m = 2 for i in test_vectors: keys, address = test_vectors[i] errmsg = f"Test vector #{int(i)}" script = p2ms(keys, m) addr = base58address.p2sh(script) self.assertEqual(addr, address, errmsg) script = scriptPubKey_from_payload("p2ms", keys, m) addr = base58address.p2sh(script) self.assertEqual(addr, address, errmsg) script_type, payload, m2 = payload_from_scriptPubKey(script) self.assertEqual(script_type, "p2ms", errmsg) for key, k in zip(sorted(keys), payload): self.assertEqual(key, k.hex(), errmsg) self.assertEqual(m2, m, errmsg)
def test_nulldata(self): script_type = "nulldata" # self-consistency string = "time-stamped data" payload = string.encode() script = encode(["OP_RETURN", payload]) # straight to the scriptPubKey scriptPubKey = nulldata(string) self.assertEqual(scriptPubKey.hex(), script.hex()) # to the scriptPubKey in two steps (through payload) scriptPubKey = scriptPubKey_from_payload(script_type, payload) self.assertEqual(scriptPubKey.hex(), script.hex()) # back from the scriptPubKey to the payload script_type2, payload2, m2 = payload_from_scriptPubKey(scriptPubKey) self.assertEqual(script_type, script_type2) self.assertEqual(0, m2) self.assertEqual(payload.hex(), payload2.hex()) script_type2, payload2, m2 = payload_from_scriptPubKey(script) self.assertEqual(script_type, script_type2) self.assertEqual(0, m2) self.assertEqual(payload.hex(), payload2.hex()) # data -> payload in this case is invertible (no hash functions) self.assertEqual(payload.decode(), string) # No address for null data script self.assertRaises(ValueError, address_from_scriptPubKey, scriptPubKey) # address_from_scriptPubKey(scriptPubKey) # documented test cases: https://learnmeabitcoin.com/guide/nulldata string = "hello world" payload = string.encode() self.assertEqual(payload.hex(), "68656c6c6f20776f726c64") script = bytes.fromhex("6a0b68656c6c6f20776f726c64") scriptPubKey = nulldata(string) self.assertEqual(scriptPubKey.hex(), script.hex()) scriptPubKey = scriptPubKey_from_payload(script_type, payload) self.assertEqual(scriptPubKey.hex(), script.hex()) script_type2, payload2, m2 = payload_from_scriptPubKey(scriptPubKey) self.assertEqual(script_type, script_type2) self.assertEqual(0, m2) self.assertEqual(payload.hex(), payload2.hex()) # documented test cases: https://learnmeabitcoin.com/guide/nulldata string = "charley loves heidi" payload = string.encode() self.assertEqual(payload.hex(), "636861726c6579206c6f766573206865696469") script = bytes.fromhex("6a13636861726c6579206c6f766573206865696469") scriptPubKey = nulldata(string) self.assertEqual(scriptPubKey.hex(), script.hex()) scriptPubKey = scriptPubKey_from_payload(script_type, payload) self.assertEqual(scriptPubKey.hex(), script.hex()) script_type2, payload2, m2 = payload_from_scriptPubKey(scriptPubKey) self.assertEqual(script_type, script_type2) self.assertEqual(0, m2) self.assertEqual(payload.hex(), payload2.hex()) # documented test cases: https://learnmeabitcoin.com/guide/nulldata string = "家族も友達もみんなが笑顔の毎日がほしい" payload = ( "e5aeb6e6978fe38282e58f8be98194e38282e381bfe38293e381aae38" "18ce7ac91e9a194e381aee6af8ee697a5e3818ce381bbe38197e38184" ) self.assertEqual(string.encode().hex(), payload) script = bytes.fromhex( "6a39e5aeb6e6978fe38282e58f8be98194e38282e381bfe38293e381aae3818c" "e7ac91e9a194e381aee6af8ee697a5e3818ce381bbe38197e38184" ) scriptPubKey = nulldata(string) self.assertEqual(scriptPubKey.hex(), script.hex()) scriptPubKey = scriptPubKey_from_payload(script_type, payload) self.assertEqual(scriptPubKey.hex(), script.hex()) script_type2, payload2, m2 = payload_from_scriptPubKey(scriptPubKey) self.assertEqual(script_type, script_type2) self.assertEqual(0, m2) self.assertEqual(payload, payload2.hex())