def test_p2pk(): pubkey = "0479BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8" signature = "304402200A5C6163F07B8D3B013C4D1D6DBA25E780B39658D79BA37AF7057A3B7F15FFA102201FD9B4EAA9943F734928B99A83592C2E7BF342EA2680F6A2BB705167966B742001" script_pubkey = script.serialize([pubkey, "OP_CHECKSIG"]) script_sig = script.serialize([signature]) founding_tx_script = script.serialize([0, 0]) founding_tx = Tx( 1, 0, vin=[ TxIn(OutPoint(b"\x00" * 32, 0xFFFFFFFF), founding_tx_script, 0xFFFFFFFF, []) ], vout=[TxOut(0, script_pubkey)], ) receiving_tx = Tx( 1, 0, vin=[TxIn(OutPoint(founding_tx.txid, 0), script_sig, 0xFFFFFFFF, [])], vout=[TxOut(0, b"")], ) sighash = get_sighash(receiving_tx, founding_tx.vout[0], 0, 0x01) assert dsa._verify(sighash, bytes.fromhex(pubkey), bytes.fromhex(signature)[:-1])
def test_p2pk_anyonecanpay(): pubkey = "048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf" signature = "304402204710a85181663b32d25c70ec2bbd14adff5ddfff6cb50d09e155ef5f541fc86c0220056b0cc949be9386ecc5f6c2ac0493269031dbb185781db90171b54ac127790281" script_pubkey = script.serialize([pubkey, "OP_CHECKSIG"]) script_sig = script.serialize([signature]) founding_tx_script = script.serialize([0, 0]) founding_tx = Tx( 1, 0, vin=[ TxIn(OutPoint(b"\x00" * 32, 0xFFFFFFFF), founding_tx_script, 0xFFFFFFFF, []) ], vout=[TxOut(0, script_pubkey)], ) receiving_tx = Tx( 1, 0, vin=[TxIn(OutPoint(founding_tx.txid, 0), script_sig, 0xFFFFFFFF, [])], vout=[TxOut(0, b"")], ) sighash = get_sighash(receiving_tx, founding_tx.vout[0], 0, 0x81) assert dsa._verify(sighash, bytes.fromhex(pubkey), bytes.fromhex(signature)[:-1])
def test_p2pkh(): pubkey = "038282263212C609D9EA2A6E3E172DE238D8C39CABD5AC1CA10646E23FD5F51508" signature = "304402206E05A6FE23C59196FFE176C9DDC31E73A9885638F9D1328D47C0C703863B8876022076FEB53811AA5B04E0E79F938EB19906CC5E67548BC555A8E8B8B0FC603D840C01" script_pubkey = script.serialize([ "OP_DUP", "OP_HASH160", "1018853670F9F3B0582C5B9EE8CE93764AC32B93", "OP_EQUALVERIFY", "OP_CHECKSIG", ]) script_sig = script.serialize([signature, pubkey]) founding_tx_script = script.serialize([0, 0]) founding_tx = Tx( 1, 0, vin=[ TxIn(OutPoint(b"\x00" * 32, 0xFFFFFFFF), founding_tx_script, 0xFFFFFFFF, []) ], vout=[TxOut(0, script_pubkey)], ) receiving_tx = Tx( 1, 0, vin=[TxIn(OutPoint(founding_tx.txid, 0), script_sig, 0xFFFFFFFF, [])], vout=[TxOut(0, b"")], ) sighash = get_sighash(receiving_tx, founding_tx.vout[0], 0, 0x01) assert dsa._verify(sighash, bytes.fromhex(pubkey), bytes.fromhex(signature)[:-1])
def test_block(): transactions = [] for x in range(10): tx_in = TxIn( prevout=OutPoint(), scriptSig=script.serialize([f"{x}{x}"]), sequence=0xFFFFFFFF, txinwitness=[], ) tx_out = TxOut( value=50 * 10**8, scriptPubKey=script.serialize([f"{x}{x}"]), ) tx = TxData( version=1, locktime=0, vin=[tx_in], vout=[tx_out], ) transactions.append(tx) header = BlockHeader( version=1, previousblockhash="00" * 32, merkleroot="00" * 32, time=1, bits=b"\x23\x00\x00\x01", nonce=1, ) header.merkleroot = _generate_merkle_root(transactions) msg = Block(BlockData(header, transactions)) msg_bytes = bytes.fromhex("00" * 4) + msg.serialize() assert msg == Block.deserialize(get_payload(msg_bytes)[1])
def generate_random_chain(length, start): # random.seed(42) chain = [] for x in range(length): previous_block_hash = chain[-1].header.hash if chain else start coinbase_in = TxIn( prevout=OutPoint(), scriptSig=script.serialize( [random.randrange(256**32).to_bytes(32, "big").hex()]), sequence=0xFFFFFFFF, txinwitness=[], ) coinbase_out = TxOut( value=50 * 10**8, scriptPubKey=script.serialize( [random.randrange(256**32).to_bytes(32, "big").hex()]), ) coinbase = Tx( version=1, locktime=0, vin=[coinbase_in], vout=[coinbase_out], ) transactions = [coinbase] if chain: tx_in = TxIn( prevout=OutPoint(chain[x - 1].transactions[0].txid, 0), scriptSig=script.serialize( [random.randrange(256**32).to_bytes(32, "big").hex()]), sequence=0xFFFFFFFF, txinwitness=[], ) tx_out = TxOut( value=50 * 10**8, scriptPubKey=script.serialize( [random.randrange(256**32).to_bytes(32, "big").hex()]), ) tx = Tx( version=1, locktime=0, vin=[tx_in], vout=[tx_out], ) transactions.append(tx) header = BlockHeader( version=70015, previousblockhash=previous_block_hash, merkleroot=_generate_merkle_root(transactions), time=1, bits=b"\x23\x00\x00\x01", nonce=1, ) block = Block(header, transactions) chain.append(block) return chain
def test_nulldata() -> None: scripts: List[List[Token]] = [["OP_RETURN", "11" * 79], ["OP_RETURN", "00" * 79]] for scriptPubKey in scripts: assert scriptPubKey == script.decode(script.encode(scriptPubKey)) assert scriptPubKey == script.decode(script.encode(scriptPubKey).hex()) assert scriptPubKey == script.deserialize( script.serialize(scriptPubKey)) assert scriptPubKey == script.deserialize( script.serialize(scriptPubKey).hex())
def test_nulldata() -> None: scripts: List[List[ScriptToken]] = [ ["OP_RETURN", "11" * 79], ["OP_RETURN", "00" * 79], ] for script_pubkey in scripts: assert script_pubkey == script.deserialize( script.serialize(script_pubkey)) assert script_pubkey == script.deserialize( script.serialize(script_pubkey).hex())
def test_p2pk() -> None: # self-consistency pubkey = "02 cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaf" scriptPubKey = script.serialize([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_simple(): script_list = [ [2, 3, "OP_ADD", 5, "OP_EQUAL"], ["1ADD", "OP_1ADD", "1ADE", "OP_EQUAL"], [hex(26)[2:].upper(), -1, "OP_ADD", hex(26)[2:].upper(), "OP_EQUAL"], [ hex(0xFFFFFFFF)[2:].upper(), -1, "OP_ADD", hex(0xFFFFFFFF)[2:].upper(), "OP_EQUAL", ], ["1F" * 250, "OP_DROP"], ["1F" * 520, "OP_DROP"], ] for script in script_list: script_bytes = encode(script) script2 = decode(script_bytes) assert script == script2 script_bytes2 = encode(script2) assert script_bytes == script_bytes2 script_serialized = serialize(script) script3 = deserialize(script_serialized) assert script == script3 script4 = deserialize(script_serialized.hex()) assert script == script4
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.serialize([0, payload]) assert scriptPubKey == p2wsh(script.deserialize(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_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.serialize([ "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_p2wsh_p2sh() -> None: # leading/trailing spaces should be tolerated pub = " 02 79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798" script_pubkey: List[ScriptToken] = [pub, "OP_CHECKSIG"] witness_script_bytes = script.serialize(script_pubkey) p2wsh_p2sh(witness_script_bytes) p2wsh_p2sh(witness_script_bytes, "testnet")
def test_simple(self): script_list = [2, 3, 'OP_ADD', 5, 'OP_EQUAL'] script_bytes = encode(script_list) script_list2 = decode(script_bytes) self.assertEqual(script_list, script_list2) script_serialized = serialize(script_list) script_list2 = parse(script_serialized) self.assertEqual(script_list, script_list2) script_list = [26, -1, 'OP_ADD', 25, 'OP_EQUAL'] script_bytes = encode(script_list) script_list2 = decode(script_bytes) self.assertEqual(script_list, script_list2) script_serialized = serialize(script_list) script_list2 = parse(script_serialized) self.assertEqual(script_list, script_list2) script_list = [0xffffffff, -1, 'OP_ADD', 0xfffffffe, 'OP_EQUAL'] script_bytes = encode(script_list) script_list2 = decode(script_bytes) self.assertEqual(script_list, script_list2) script_serialized = serialize(script_list) script_list2 = parse(script_serialized) self.assertEqual(script_list, script_list2) script_list = ["1f" * 250, 'OP_DROP'] script_bytes = encode(script_list) script_list2 = decode(script_bytes) self.assertEqual(script_list, script_list2) script_serialized = serialize(script_list) script_list2 = parse(script_serialized) self.assertEqual(script_list, script_list2) script_list = ["1f" * 520, 'OP_DROP'] script_bytes = encode(script_list) script_list2 = decode(script_bytes.hex()) self.assertEqual(script_list, script_list2) script_serialized = serialize(script_list) script_list2 = parse(script_serialized.hex()) self.assertEqual(script_list, script_list2)
def test_nulldata() -> None: # self-consistency string = "time-stamped data" payload = string.encode() script_pubkey = script.serialize(["OP_RETURN", payload]) assert script_pubkey == nulldata(string) # to the script_pubkey in two steps (through payload) script_type = "nulldata" assert script_pubkey == script_pubkey_from_payload(script_type, payload) # back from the script_pubkey to the payload assert (script_type, payload, 0) == payload_from_script_pubkey(script_pubkey) # data -> payload in this case is invertible (no hash functions) assert payload.decode("ascii") == string err_msg = "no address for null data script" with pytest.raises(BTClibValueError, match=err_msg): address_from_script_pubkey(script_pubkey) # documented test cases: https://learnmeabitcoin.com/guide/nulldata string = "hello world" payload = string.encode() assert payload.hex() == "68656c6c6f20776f726c64" # pylint: disable=no-member script_pubkey = b"\x6a\x0b" + payload assert script_pubkey == nulldata(string) assert script_pubkey == script_pubkey_from_payload(script_type, payload) assert (script_type, payload, 0) == payload_from_script_pubkey(script_pubkey) # documented test cases: https://learnmeabitcoin.com/guide/nulldata string = "charley loves heidi" payload = string.encode() assert (payload.hex() # pylint: disable=no-member == "636861726c6579206c6f766573206865696469") script_pubkey = b"\x6a\x13" + payload assert script_pubkey == nulldata(string) assert script_pubkey == script_pubkey_from_payload(script_type, payload) assert (script_type, payload, 0) == payload_from_script_pubkey(script_pubkey) # documented test cases: https://learnmeabitcoin.com/guide/nulldata string = "家族も友達もみんなが笑顔の毎日がほしい" payload = string.encode() assert ( payload.hex() # pylint: disable=no-member == "e5aeb6e6978fe38282e58f8be98194e38282e381bfe38293e381aae3818ce7ac91e9a194e381aee6af8ee697a5e3818ce381bbe38197e38184" ) script_pubkey = b"\x6a\x39" + payload assert script_pubkey == nulldata(string) assert script_pubkey == script_pubkey_from_payload(script_type, payload) assert (script_type, payload, 0) == payload_from_script_pubkey(script_pubkey)
def test_tx(): tx_in = TxIn( prevout=OutPoint(), scriptSig=script.serialize(["00"]), sequence=0xFFFFFFFF, txinwitness=[], ) tx_out = TxOut( value=50 * 10**8, scriptPubKey=script.serialize(["00"]), ) tx = TxData( version=1, locktime=0, vin=[tx_in], vout=[tx_out], ) msg = Tx(tx) msg_bytes = bytes.fromhex("00" * 4) + msg.serialize() assert msg == Tx.deserialize(get_payload(msg_bytes)[1])
def test_simple() -> None: script_list: List[List[ScriptToken]] = [ [2, 3, "OP_ADD", 5, "OP_EQUAL"], ["1ADD", "OP_1ADD", "1ADE", "OP_EQUAL"], [hex(26)[2:].upper(), -1, "OP_ADD", hex(26)[2:].upper(), "OP_EQUAL"], [ hex(0xFFFFFFFF)[2:].upper(), -1, "OP_ADD", hex(0xFFFFFFFF)[2:].upper(), "OP_EQUAL", ], ["1F" * 250, "OP_DROP"], ["1F" * 520, "OP_DROP"], ] for script_pubkey in script_list: assert script_pubkey == script.deserialize( script.serialize(script_pubkey)) assert script_pubkey == script.deserialize( script.serialize(script_pubkey).hex())
def create_genesis(time, nonce, difficulty, version, reward): script_sig = script.serialize( [ "FFFF001D", b"\x04", "The Times 03/Jan/2009 Chancellor on brink of second bailout for banks".encode(), ] ) script_pub_key = script.serialize( [ "04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f", "OP_CHECKSIG", ] ) tx_in = TxIn( prevout=OutPoint(), scriptSig=script_sig, sequence=0xFFFFFFFF, txinwitness=[], ) tx_out = TxOut( value=reward, scriptPubKey=script_pub_key, ) tx = Tx( version=1, locktime=0, vin=[tx_in], vout=[tx_out], ) header = BlockHeader( version=version, previousblockhash="00" * 32, merkleroot="00" * 32, time=time, bits=difficulty.to_bytes(4, "big"), nonce=nonce, ) header.merkleroot = _generate_merkle_root([tx]) return header
def test_p2sh() -> None: # https://medium.com/@darosior/bitcoin-raw-transactions-part-2-p2sh-94df206fee8d scriptPubKey: List[ScriptToken] = [ "OP_2DUP", "OP_EQUAL", "OP_NOT", "OP_VERIFY", "OP_SHA1", "OP_SWAP", "OP_SHA1", "OP_EQUAL", ] assert script.serialize(scriptPubKey).hex() == "6e879169a77ca787" network = "mainnet" addr = p2sh(scriptPubKey, network) assert addr == b"37k7toV1Nv4DfmQbmZ8KuZDQCYK9x5KpzP" _, redeem_script_hash, network2, is_script_hash = h160_from_b58address( addr) assert network == network2 assert is_script_hash assert redeem_script_hash == hash160(script.serialize(scriptPubKey)) assert redeem_script_hash.hex( ) == "4266fc6f2c2861d7fe229b279a79803afca7ba34" output_script: List[ScriptToken] = [ "OP_HASH160", redeem_script_hash.hex(), "OP_EQUAL", ] script.serialize(output_script) # address with trailing/leading spaces _, h160, network2, is_script_hash = h160_from_b58address( " 37k7toV1Nv4DfmQbmZ8KuZDQCYK9x5KpzP ") assert network == network2 assert is_script_hash assert redeem_script_hash == h160
def test_blocktxn(): transactions = [] for x in range(10): tx_in = TxIn( prevout=OutPoint(), scriptSig=script.serialize([f"{x}{x}"]), sequence=0xFFFFFFFF, txinwitness=[], ) tx_out = TxOut( value=50 * 10**8, scriptPubKey=script.serialize([f"{x}{x}"]), ) tx = TxData( version=1, locktime=0, vin=[tx_in], vout=[tx_out], ) transactions.append(tx) msg = Blocktxn("00" * 32, transactions) msg_bytes = bytes.fromhex("00" * 4) + msg.serialize() assert msg == Blocktxn.deserialize(get_payload(msg_bytes)[1])
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.serialize(["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.deserialize(scriptPubKey))
def test_legacy_p2pkh(): pubkey = "04280c8f66bf2ccaeb3f60a19ad4a06365f8bd6178aab0e709df2173df8f553366549aec336aae8742a84702b6c7c3052d89f5d76d535ec3716e72187956351613" signature = "3045022100ea43c4800d1a860ec89b5273898a146cfb01d34ff4c364d24a110c480d0e3f7502201c82735577f932f1ca8e1c54bf653e0f8e74e408fe83666bc85cac4472ec950801" script_sig = [signature, pubkey] previous_txout = TxOut( value=1051173696, script_pubkey=script.serialize([ "OP_DUP", "OP_HASH160", "82ac30f58baf99ec9d14e6181eee076f4e27f69c", "OP_EQUALVERIFY", "OP_CHECKSIG", ]), ) tx = Tx( 1, 0, vin=[ TxIn( OutPoint( bytes.fromhex( "d8343a35ba951684f2969eafe833d9e6fe436557b9707ae76802875952e860fc" ), 1, ), script_sig, 0xFFFFFFFF, [], ) ], vout=[ TxOut( 2017682, bytes.fromhex( "76a91413bd20236d0da56492c325dce289b4da35b4b5bd88ac"), ), TxOut( 1049154982, bytes.fromhex( "76a914da169b45781ca210f8c11617ba66bd843da76b1688ac"), ), ], ) sighash = get_sighash(tx, previous_txout, 0, 0x01) assert dsa._verify(sighash, bytes.fromhex(pubkey), bytes.fromhex(signature)[:-1])
def test_p2pkh() -> None: # self-consistency pubkey = ( "04 " "cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaf" "f7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4") payload = hash160(pubkey) script_pubkey = script.serialize( ["OP_DUP", "OP_HASH160", payload, "OP_EQUALVERIFY", "OP_CHECKSIG"]) assert script_pubkey == p2pkh(pubkey) # to the script_pubkey in two steps (through payload) script_type = "p2pkh" assert script_pubkey == script_pubkey_from_payload(script_type, payload) # back from the script_pubkey to the payload assert (script_type, payload, 0) == payload_from_script_pubkey(script_pubkey) # base58 address network = "mainnet" address = base58address.p2pkh(pubkey, network) assert address == address_from_script_pubkey(script_pubkey, network) prefix = NETWORKS[network].p2pkh assert address == b58address_from_h160(prefix, payload, network) # back from the address to the script_pubkey assert (script_pubkey, network) == script_pubkey_from_address(address) # documented test case: https://learnmeabitcoin.com/guide/p2pkh payload = "12ab8dc588ca9d5787dde7eb29569da63c3a238c" script_pubkey = "76a914" + payload + "88ac" assert script_pubkey == script_pubkey_from_payload(script_type, payload).hex() address = b"12higDjoCCNXSA95xZMWUdPvXNmkAduhWv" assert address == address_from_script_pubkey(script_pubkey, network) assert (bytes.fromhex(script_pubkey), network) == script_pubkey_from_address(address) # invalid size: 11 bytes instead of 20 err_msg = "invalid size: " with pytest.raises(BTClibValueError, match=err_msg): script_pubkey_from_payload(script_type, "00" * 11)
def test_sighashsingle_bug(): pubkey = "02D5C25ADB51B61339D2B05315791E21BBE80EA470A49DB0135720983C905AACE0" signature = "3045022100C9CDD08798A28AF9D1BAF44A6C77BCC7E279F47DC487C8C899911BC48FEAFFCC0220503C5C50AE3998A733263C5C0F7061B483E2B56C4C41B456E7D2F5A78A74C07703" script_pubkey = script.serialize([ "OP_DUP", "OP_HASH160", "5b6462475454710f3c22f5fdf0b40704c92f25c3", "OP_EQUALVERIFY", "OP_CHECKSIGVERIFY", 1, ]) previous_txout = TxOut(0, script_pubkey) tx = Tx.deserialize( "01000000020002000000000000000000000000000000000000000000000000000000000000000000000151ffffffff0001000000000000000000000000000000000000000000000000000000000000000000006b483045022100c9cdd08798a28af9d1baf44a6c77bcc7e279f47dc487c8c899911bc48feaffcc0220503c5c50ae3998a733263c5c0f7061b483e2b56c4c41b456e7d2f5a78a74c077032102d5c25adb51b61339d2b05315791e21bbe80ea470a49db0135720983c905aace0ffffffff010000000000000000015100000000" ) sighash = get_sighash(tx, previous_txout, 1, 0x03) assert dsa._verify(sighash, bytes.fromhex(pubkey), bytes.fromhex(signature)[:-1])
def test_p2sh() -> None: # self-consistency pubkey = "02 cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaf" pubkey_hash = hash160(pubkey) redeem_script = script_pubkey_from_payload("p2pkh", pubkey_hash) payload = hash160(redeem_script) script_pubkey = script.serialize(["OP_HASH160", payload, "OP_EQUAL"]) assert script_pubkey == p2sh(redeem_script) # to the script_pubkey in two steps (through payload) script_type = "p2sh" assert script_pubkey == script_pubkey_from_payload(script_type, payload) # back from the script_pubkey to the payload assert (script_type, payload, 0) == payload_from_script_pubkey(script_pubkey) # base58 address network = "mainnet" address = base58address.p2sh(script.deserialize(redeem_script), network) assert address == address_from_script_pubkey(script_pubkey, network) prefix = NETWORKS[network].p2sh assert address == b58address_from_h160(prefix, payload, network) # back from the address to the script_pubkey assert (script_pubkey, network) == script_pubkey_from_address(address) # documented test case: https://learnmeabitcoin.com/guide/p2sh payload = "748284390f9e263a4b766a75d0633c50426eb875" script_pubkey = "a914" + payload + "87" assert script_pubkey == script_pubkey_from_payload(script_type, payload).hex() address = b"3CK4fEwbMP7heJarmU4eqA3sMbVJyEnU3V" assert address == address_from_script_pubkey(script_pubkey, network) assert (bytes.fromhex(script_pubkey), network) == script_pubkey_from_address(address) # invalid size: 21 bytes instead of 20 err_msg = "invalid size: " with pytest.raises(BTClibValueError, match=err_msg): script_pubkey_from_payload(script_type, "00" * 21)
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.serialize( [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_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.serialize([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_exceptions() -> None: script_pubkey: List[ScriptToken] = [2, 3, "OP_ADD", 5, "OP_RETURN_244"] err_msg = "invalid string token: OP_RETURN_244" with pytest.raises(BTClibValueError, match=err_msg): script.serialize(script_pubkey) err_msg = "Unmanaged <class 'function'> token type" with pytest.raises(BTClibValueError, match=err_msg): script.serialize([2, 3, "OP_ADD", 5, script.serialize]) # type: ignore script_pubkey = ["1f" * 521, "OP_DROP"] err_msg = "Too many bytes for OP_PUSHDATA: " with pytest.raises(BTClibValueError, match=err_msg): script.serialize(script_pubkey) # A script_pubkey with OP_PUSHDATA4 can be decoded script_bytes = "4e09020000" + "00" * 521 + "75" # ['00'*521, 'OP_DROP'] script_pubkey = script.deserialize(script_bytes) # but it cannot be encoded err_msg = "Too many bytes for OP_PUSHDATA: " with pytest.raises(BTClibValueError, match=err_msg): script.serialize(script_pubkey)
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: witvers, witprog, network, _ = witness_from_b32address(address) script_pubkey: List[ScriptToken] = [witvers, witprog] assert script.serialize(script_pubkey).hex() == hexscript addr = b32address_from_witness(witvers, witprog, network) assert address.lower().strip() == addr.decode("ascii")
def test_p2wsh() -> None: # https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki pub = "02 79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798" script_pubkey: List[ScriptToken] = [pub, "OP_CHECKSIG"] witness_script_bytes = script.serialize(script_pubkey) addr = b"tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7" assert addr == p2wsh(witness_script_bytes, "testnet") _, wp, _, _ = witness_from_b32address(addr) assert bytes(wp) == sha256(witness_script_bytes) addr = b"bc1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qccfmv3" assert addr == p2wsh(witness_script_bytes) _, wp, _, _ = witness_from_b32address(addr) assert bytes(wp) == sha256(witness_script_bytes) assert witness_from_b32address(addr)[1] == sha256(witness_script_bytes) err_msg = "invalid witness program length for witness v0: " with pytest.raises(BTClibValueError, match=err_msg): b32address_from_witness(0, witness_script_bytes)
def test_nulldata3() -> None: err_msg = "invalid nulldata script length: " with pytest.raises(ValueError, match=err_msg): payload = "00" * 81 scriptPubKey_from_payload("nulldata", payload) # wrong data length: 32 in 35-bytes nulldata script; # it should have been 33 scriptPubKey = script.serialize(["OP_RETURN", b"\x00" * 33]) scriptPubKey = scriptPubKey[:1] + b"\x20" + scriptPubKey[2:] err_msg = "wrong data length: " with pytest.raises(ValueError, match=err_msg): payload_from_scriptPubKey(scriptPubKey) # wrong data length: 32 in 83-bytes nulldata script; # it should have been 80 scriptPubKey = script.serialize(["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.serialize(["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.serialize(["OP_RETURN", b"\x00" * 75])) == 77 assert len(script.serialize(["OP_RETURN", b"\x00" * 76])) == 79 scriptPubKey = script.serialize(["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)