def get_address(self, offset=0, is_change=False, sort_keys=True): """ If is_change=True, then we display change addresses. If is_change=False we display receive addresses. sort_keys is for expert users only and should be left as True """ assert type(is_change) is bool, is_change assert type(offset) is int and offset >= 0, offset sec_hexes_to_use = [] for key_record in self.key_records: hdpubkey = HDPublicKey.parse(key_record["xpub_parent"]) if is_change is True: account = key_record["account_index"] + 1 else: account = key_record["account_index"] leaf_xpub = hdpubkey.child(account).child(offset) sec_hexes_to_use.append(leaf_xpub.sec().hex()) commands = [number_to_op_code(self.quorum_m)] if sort_keys: # BIP67 lexicographical sorting for sortedmulti commands.extend([bytes.fromhex(x) for x in sorted(sec_hexes_to_use)]) else: commands.extend([bytes.fromhex(x) for x in sec_hexes_to_use]) commands.append(number_to_op_code(len(self.key_records))) commands.append(174) # OP_CHECKMULTISIG witness_script = WitnessScript(commands) redeem_script = P2WSHScriptPubKey(sha256(witness_script.raw_serialize())) return redeem_script.address(network=self.network)
def _get_address(pubkey_dicts, quorum_m, quorum_n, index, is_testnet): sec_hexes_to_use = [] for pubkey_dict in pubkey_dicts: leaf_xpub = pubkey_dict["child_pubkey_obj"].child(index=index) sec_hexes_to_use.append(leaf_xpub.sec().hex()) commands = [OP_CODE_NAMES_LOOKUP["OP_{}".format(quorum_m)]] commands.extend([bytes.fromhex(x) for x in sorted(sec_hexes_to_use)]) # BIP67 commands.append(OP_CODE_NAMES_LOOKUP["OP_{}".format(quorum_n)]) commands.append(OP_CODE_NAMES_LOOKUP["OP_CHECKMULTISIG"]) witness_script = WitnessScript(commands) redeem_script = P2WSHScriptPubKey(sha256(witness_script.raw_serialize())) return redeem_script.address(testnet=is_testnet)
def test_p2wsh_with_quorum(self): p2wsh_script_hex = "ad51210236a6cf4254c8290a168ecab4aee771018d357ea87154a5b5fea9ed9baee2585e210355ec1001c2c4f1dce2de940beacbdcb7d7746140281a9283000aa46d251d46312103833d6e7c4121180fb79180b78a0573ad57c299825f18f49f6942cb38b6bf023a2103a9e341c32d8870706115443cf163bfc3d2da0ca8515a29bcc1a500c65cfb23bb2103b2ac11803043c0db884dcddfdcff02599324d5e747b26e4235f57b8019fae04155ae" witness_script = WitnessScript.parse(BytesIO(bytes.fromhex((p2wsh_script_hex)))) want = "OP_1 0236a6cf4254c8290a168ecab4aee771018d357ea87154a5b5fea9ed9baee2585e 0355ec1001c2c4f1dce2de940beacbdcb7d7746140281a9283000aa46d251d4631 03833d6e7c4121180fb79180b78a0573ad57c299825f18f49f6942cb38b6bf023a 03a9e341c32d8870706115443cf163bfc3d2da0ca8515a29bcc1a500c65cfb23bb 03b2ac11803043c0db884dcddfdcff02599324d5e747b26e4235f57b8019fae041 OP_5 OP_CHECKMULTISIG " self.assertEqual(str(witness_script), want) self.assertTrue(witness_script.is_p2wsh_multisig()) self.assertEqual(witness_script.get_quorum(), (1, 5)) # 1-of-5
def sig_hash(self, input_index, hash_type): # get the relevant input tx_in = self.tx_ins[input_index] # get the script_pubkey of the input script_pubkey = tx_in.script_pubkey(network=self.network) # grab the RedeemScript if we have a p2sh if script_pubkey.is_p2sh(): # the last command of the ScriptSig is the raw RedeemScript raw_redeem_script = tx_in.script_sig.commands[-1] # convert to RedeemScript redeem_script = RedeemScript.convert(raw_redeem_script) else: redeem_script = None # grab the WitnessScript if we have a p2wsh if script_pubkey.is_p2wsh() or (redeem_script and redeem_script.is_p2wsh()): # the last item of the Witness is the raw WitnessScript raw_witness_script = tx_in.witness.items[-1] # convert to WitnessScript witness_script = WitnessScript.convert(raw_witness_script) else: witness_script = None # check to see if the ScriptPubKey or the RedeemScript is p2wpkh or p2wsh if (script_pubkey.is_p2wpkh() or (redeem_script and redeem_script.is_p2wpkh()) or script_pubkey.is_p2wsh() or (redeem_script and redeem_script.is_p2wsh())): return self.sig_hash_bip143( input_index, redeem_script=redeem_script, witness_script=witness_script, hash_type=hash_type, ) elif script_pubkey.is_p2tr(): if len(tx_in.witness) > 1: ext_flag = 1 else: ext_flag = 0 return self.sig_hash_bip341(input_index, ext_flag=ext_flag, hash_type=hash_type) else: return self.sig_hash_legacy(input_index, redeem_script, hash_type=hash_type)
def test_sign_p2sh_p2wsh_multisig(self): private_key1 = PrivateKey(secret=8675309) private_key2 = PrivateKey(secret=8675310) witness_script = WitnessScript( [0x52, private_key1.point.sec(), private_key2.point.sec(), 0x52, 0xAE] ) prev_tx = bytes.fromhex( "f92c8c8e40296c6a94539b6d22d8994a56dd8ff2d6018d07a8371fef1f66efee" ) prev_index = 0 fee = 500 tx_in = TxIn(prev_tx, prev_index) amount = tx_in.value(network="testnet") - fee tx_out = TxOut.to_address("mqYz6JpuKukHzPg94y4XNDdPCEJrNkLQcv", amount) t = Tx(1, [tx_in], [tx_out], 0, network="testnet", segwit=True) sig1 = t.get_sig_segwit(0, private_key1, witness_script=witness_script) sig2 = t.get_sig_segwit(0, private_key2, witness_script=witness_script) self.assertTrue( t.check_sig_segwit( 0, private_key1.point, Signature.parse(sig1[:-1]), witness_script=witness_script, ) ) self.assertTrue( t.check_sig_segwit( 0, private_key2.point, Signature.parse(sig2[:-1]), witness_script=witness_script, ) ) tx_in.finalize_p2sh_p2wsh_multisig([sig1, sig2], witness_script) want = "01000000000101eeef661fef1f37a8078d01d6f28fdd564a99d8226d9b53946a6c29408e8c2cf900000000232200206ddafd1089f07a2ba9868df71f622801fe11f5452c6ff1f8f51573133828b437ffffffff014c400f00000000001976a9146e13971913b9aa89659a9f53d327baa8826f2d7588ac0400483045022100d31433973b7f8014a4e17d46c4720c6c9bed1ee720dc1f0839dd847fa6972553022039278e98a3c18f4748a2727b99acd41eb1534dcf041a3abefd0c7546c868f55801473044022027be7d616b0930c1edf7ed39cc99edf5975e7b859d3224fe340d55c595c2798f02206c05662d39e5b05cc13f936360d62a482b122ad9791074bbdafec3ddc221b8c00147522103935581e52c354cd2f484fe8ed83af7a3097005b2f9c60bff71d35bd795f54b672103674944c63d8dc3373a88cd1f8403b39b48be07bdb83d51dbbaa34be070c72e1452ae00000000" self.assertEqual(t.serialize().hex(), want)
def test_sign_p2wsh_multisig(self): private_key1 = PrivateKey(secret=8675309) private_key2 = PrivateKey(secret=8675310) witness_script = WitnessScript( [0x52, private_key1.point.sec(), private_key2.point.sec(), 0x52, 0xAE] ) prev_tx = bytes.fromhex( "61cd20e3ffdf9216cee9cd607e1a65d3096513c4df3a63d410c047379b54a94a" ) prev_index = 1 fee = 500 tx_in = TxIn(prev_tx, prev_index) amount = tx_in.value(network="testnet") - fee tx_out = TxOut.to_address("mqYz6JpuKukHzPg94y4XNDdPCEJrNkLQcv", amount) t = Tx(1, [tx_in], [tx_out], 0, network="testnet", segwit=True) sig1 = t.get_sig_segwit(0, private_key1, witness_script=witness_script) sig2 = t.get_sig_segwit(0, private_key2, witness_script=witness_script) self.assertTrue( t.check_sig_segwit( 0, private_key1.point, Signature.parse(sig1[:-1]), witness_script=witness_script, ) ) self.assertTrue( t.check_sig_segwit( 0, private_key2.point, Signature.parse(sig2[:-1]), witness_script=witness_script, ) ) tx_in.finalize_p2wsh_multisig([sig1, sig2], witness_script) want = "010000000001014aa9549b3747c010d4633adfc4136509d3651a7e60cde9ce1692dfffe320cd610100000000ffffffff014c400f00000000001976a9146e13971913b9aa89659a9f53d327baa8826f2d7588ac04004730440220325e9f389c4835dab74d644e8c8e295535d9b082d28aefc3fa127e23538051bd022050d68dcecda660d4c01a8443c2b30bd0b3e4b1a405b0f352dcb068210862f6810147304402201abceabfc94903644cf7be836876eaa418cb226e03554c17a71c65b232f4507302202105a8344abae9632d1bc8249a52cf651c4ea02ca5259e20b50d8169c949f5a20147522103935581e52c354cd2f484fe8ed83af7a3097005b2f9c60bff71d35bd795f54b672103674944c63d8dc3373a88cd1f8403b39b48be07bdb83d51dbbaa34be070c72e1452ae00000000" self.assertEqual(t.serialize().hex(), want)
def test_p2sh_address(self): witness_script_hex = "5221026ccfb8061f235cc110697c0bfb3afb99d82c886672f6b9b5393b25a434c0cbf32103befa190c0c22e2f53720b1be9476dcf11917da4665c44c9c71c3a2d28a933c352102be46dc245f58085743b1cc37c82f0d63a960efa43b5336534275fc469b49f4ac53ae" witness_script = WitnessScript.convert(bytes.fromhex(witness_script_hex)) want = "2MvVx9ccWqyYVNa5Xz9pfCEVk99zVBZh9ms" self.assertEqual(witness_script.p2sh_address(network="testnet"), want) self.assertEqual(witness_script.p2sh_address(network="signet"), want)
def test_address(self): witness_script_hex = "52210375e00eb72e29da82b89367947f29ef34afb75e8654f6ea368e0acdfd92976b7c2103a1b26313f430c4b15bb1fdce663207659d8cac749a0e53d70eff01874496feff2103c96d495bfdd5ba4145e3e046fee45e84a8a48ad05bd8dbb395c011a32cf9f88053ae" witness_script = WitnessScript.convert(bytes.fromhex(witness_script_hex)) want = "bc1qwqdg6squsna38e46795at95yu9atm8azzmyvckulcc7kytlcckxswvvzej" self.assertEqual(witness_script.address(), want)