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 assert_signable(self) -> None: self.assert_valid() for i, tx_in in enumerate(self.tx.vin): non_witness_utxo = self.inputs[i].non_witness_utxo witness_utxo = self.inputs[i].witness_utxo redeem_script = self.inputs[i].redeem_script if witness_utxo: script_pub_key = witness_utxo.script_pub_key script_type, payload = type_and_payload(script_pub_key.script) if script_type == "p2sh": script_type, _ = type_and_payload(redeem_script) if script_type not in ("p2wpkh", "p2wsh"): raise BTClibValueError( "script type not it ('p2wpkh', 'p2wsh')") elif non_witness_utxo: script_pub_key = non_witness_utxo.vout[ tx_in.prev_out.vout].script_pub_key _, payload = type_and_payload(script_pub_key.script) else: err_msg = "missing script_pub_key" raise BTClibValueError(err_msg) if redeem_script and payload != hash160(redeem_script): raise BTClibValueError("invalid redeem script hash160") if self.inputs[i].witness_script: if redeem_script: _, payload = type_and_payload(redeem_script) if payload != sha256(self.inputs[i].witness_script): raise BTClibValueError("invalid witness script sha256")
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_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)
def p2wsh( cls: Type["ScriptPubKey"], redeem_script: Octets, network: str = "mainnet", check_validity: bool = True, ) -> "ScriptPubKey": "Return the p2wsh ScriptPubKey of the provided redeem script." script_h256 = sha256(redeem_script) script = serialize(["OP_0", script_h256]) return cls(script, network, check_validity)
def _assert_valid_sha256_preimages( sha256_preimages: Mapping[bytes, bytes]) -> None: for h, preimage in sha256_preimages.items(): if sha256(preimage) != h: raise BTClibValueError("Invalid SHA256 preimage")
def p2wsh_p2sh(redeem_script: Octets, network: str = "mainnet") -> str: "Return the p2wsh-p2sh base58 address corresponding to a reedem script." witness_program = sha256(redeem_script) return _address_from_v0_witness(witness_program, network)
def taproot( transaction: Tx, input_index: int, amounts: List[int], scriptpubkeys: List[ScriptPubKey], hashtype: int, ext_flag: int, annex: bytes, message_extension: bytes, ) -> bytes: if hashtype not in SIG_HASH_TYPES: raise BTClibValueError(f"Unknown hash type: {hashtype}") if hashtype & 0x03 == SINGLE and input_index >= len(transaction.vout): raise BTClibValueError("Sighash single wihout a corresponding output") preimage = b"\x00" preimage += hashtype.to_bytes(1, "little") preimage += transaction.nVersion.to_bytes(4, "little") preimage += transaction.nLockTime.to_bytes(4, "little") if hashtype & 0x80 != ANYONECANPAY: sha_prevouts = b"" sha_amounts = b"" sha_scriptpubkeys = b"" sha_sequences = b"" for i, vin in enumerate(transaction.vin): sha_prevouts += vin.prev_out.serialize() sha_amounts += amounts[i].to_bytes(8, "little") sha_scriptpubkeys += var_bytes.serialize(scriptpubkeys[i].script) sha_sequences += vin.nSequence.to_bytes(4, "little") preimage += sha256(sha_prevouts) preimage += sha256(sha_amounts) preimage += sha256(sha_scriptpubkeys) preimage += sha256(sha_sequences) if hashtype & 0x03 not in [NONE, SINGLE]: sha_outputs = b"" for vout in transaction.vout: sha_outputs += vout.serialize() preimage += sha256(sha_outputs) annex_present = int(bool(annex)) preimage += (2 * ext_flag + annex_present).to_bytes(1, "little") if hashtype & 0x80 == ANYONECANPAY: preimage += transaction.vin[input_index].prev_out.serialize() preimage += amounts[input_index].to_bytes(8, "little") preimage += var_bytes.serialize(scriptpubkeys[input_index].script) preimage += transaction.vin[input_index].nSequence.to_bytes( 4, "little") else: preimage += input_index.to_bytes(4, "little") if annex_present: sha_annex = var_bytes.serialize(annex) preimage += sha256(sha_annex) if hashtype & 0x03 == SINGLE: preimage += sha256(transaction.vout[input_index].serialize()) preimage += message_extension sig_hash = tagged_hash(b"TapSighash", preimage) return sig_hash
def p2wsh(script_pub_key: Octets, network: str = "mainnet") -> str: "Return the p2wsh bech32 address corresponding to a script_pub_key." h256 = sha256(script_pub_key) return address_from_witness(0, h256, network)