コード例 #1
0
 def test_get_xpub(self):
     res = sim.query(b"fingerprint")
     self.assertEqual(res, b"73c5da0a")
     res = sim.query(b"xpub m/44h/1h/0h")
     self.assertEqual(
         res,
         b"tpubDC5FSnBiZDMmhiuCmWAYsLwgLYrrT9rAqvTySfuCCrgsWz8wxMXUS9Tb9iVMvcRbvFcAHGkMD5Kx8koh4GquNGNTfohfk7pgjhaPCdXpoba"
     )
コード例 #2
0
    def sign_with_descriptor(self, wname, d1, d2, all_sighashes=False):
        # to derive addresses
        desc1 = Descriptor.from_string(d1)
        desc2 = Descriptor.from_string(d2)
        # recv addr 2
        addr1 = desc1.derive(2).address(NETWORKS['regtest'])
        # change addr 3
        addr2 = desc2.derive(3).address(NETWORKS['regtest'])
        res = sim.query(f"bitcoin:{addr1}?index=2", [True])
        # check it's found
        self.assertFalse(b"Can't find wallet" in res)

        # to add checksums
        d1 = rpc.getdescriptorinfo(d1)["descriptor"]
        d2 = rpc.getdescriptorinfo(d2)["descriptor"]
        rpc.createwallet(wname, True, True)
        w = rpc.wallet(wname)
        res = w.importmulti([{
                "desc": d1,
                "internal": False,
                "timestamp": "now",
                "watchonly": True,
                "range": 10,
            },{
                "desc": d2,
                "internal": True,
                "timestamp": "now",
                "watchonly": True,
                "range": 10,
            }],{"rescan": False})
        self.assertTrue(all([k["success"] for k in res]))
        wdefault.sendtoaddress(addr1, 0.1)
        rpc.mine()
        psbt = w.walletcreatefundedpsbt([], [{wdefault.getnewaddress(): 0.002}], 0, {"includeWatching": True, "changeAddress": addr2}, True)
        unsigned = psbt["psbt"]
        sighashes = [None]
        if all_sighashes:
            sh = [SIGHASH.ALL, SIGHASH.NONE, SIGHASH.SINGLE]
            sighashes += sh + [s | SIGHASH.ANYONECANPAY for s in sh]
        tx = PSBT.from_base64(unsigned)
        for sh in sighashes:
            for inp in tx.inputs:
                inp.sighash_type = sh
            unsigned = tx.to_base64().encode()
            # confirm signing
            if sh in [SIGHASH.ALL, None]:
                signed = sim.query(b"sign "+unsigned, [True])
            else:
                # confirm warning
                signed = sim.query(b"sign "+unsigned, [True, True])
            # signed tx
            self.assertTrue(signed.startswith(b"cHNi"))
            combined = rpc.combinepsbt([unsigned.decode(), signed.decode()])
            final = rpc.finalizepsbt(combined)
            self.assertTrue(final["complete"])
            # broadcast
            res = rpc.testmempoolaccept([final["hex"]])
            self.assertTrue(res[0]["allowed"])
コード例 #3
0
    def test_sign_psbt(self):
        unsigned = b"cHNidP8BAHECAAAAAQWaIPxj7qSA0cbaKKz5Lk43V/8/FZeQw+IQ2tV6eJnbAAAAAAD9////AgfVTQUAAAAAFgAUUzfXvW1SC/+493dPMkR+9Ua1+7mAlpgAAAAAABYAFCwSoUTerJLG437IpfbWF8DgWx6kAAAAAAABAR8Kl+YFAAAAABYAFC80qhzwClOwVaKRoDp9RfCmmItSIgYDXUnszVTQCZ5DZ2J3x6bUYl1hHaiKXfSb+VF6d5Gnd6UYc8XaClQAAIABAACAAAAAgAEAAAAAAAAAACICAzra7/AYOHv1KHXP0Kgv8paA8ELhUBDLW3FrKXZzZpg2GHPF2gpUAACAAQAAgAAAAIABAAAAAgAAAAAA"
        # confirm signing
        res = sim.query(b"sign " + unsigned, [True])
        # signed tx
        self.assertEqual(
            res,
            b"cHNidP8BAHECAAAAAQWaIPxj7qSA0cbaKKz5Lk43V/8/FZeQw+IQ2tV6eJnbAAAAAAD9////AgfVTQUAAAAAFgAUUzfXvW1SC/+493dPMkR+9Ua1+7mAlpgAAAAAABYAFCwSoUTerJLG437IpfbWF8DgWx6kAAAAAAAiAgNdSezNVNAJnkNnYnfHptRiXWEdqIpd9Jv5UXp3kad3pUcwRAIgDf80duROzcio5iPQ/RbThlXHzr2tmqFaIHR1SOMHHT8CIDGUwTINLkmIk6onOGtlFSQYibQfjhIkRxmx1LJa0NNGAQAAAA=="
        )

        # cancel signing
        res = sim.query(b"sign " + unsigned, [False])
        self.assertEqual(res, b"error: User cancelled")
コード例 #4
0
    def test_wpkh(self):
        """Native segwit single-sig"""
        path = "84h/1h/0h"
        fgp = sim.query("fingerprint").decode()
        xpub = sim.query(f"xpub m/{path}").decode()
        d1 = f"wpkh([{fgp}/{path}]{xpub}/0/*)"
        d2 = f"wpkh([{fgp}/{path}]{xpub}/1/*)"
        wname = wallet_prefix+"_wpkh"

        addr = Descriptor.from_string(d1).derive(5).address(NETWORKS['regtest'])
        # check it finds the wallet correctly
        res = sim.query(f"showaddr wpkh m/{path}/0/5", [True])
        self.assertEqual(res.decode(), addr)

        self.sign_with_descriptor(wname, d1, d2)
コード例 #5
0
    def test_strange_derivation(self):
        path = "84h/1h/0h"
        fgp = sim.query("fingerprint").decode()
        xpub = sim.query(f"xpub m/{path}").decode()
        d1 = f"wpkh([{fgp}/{path}]{xpub}/44/8/*)"
        d2 = f"wpkh([{fgp}/{path}]{xpub}/55/8/*)"
        # combined with default derivation {0,1}/*
        d3 = f"wpkh([{fgp}/{path}]{xpub}"+ "/{44,55}/8/*)"
        res = sim.query("addwallet weird&"+d3, [True])

        addr = Descriptor.from_string(d1).derive(5).address(NETWORKS['regtest'])
        # check it finds the wallet correctly
        res = sim.query(f"showaddr wpkh m/{path}/44/8/5", [True])
        self.assertEqual(res.decode(), addr)

        wname = wallet_prefix+"_weird"
        self.sign_with_descriptor(wname, d1, d2)
コード例 #6
0
    def test_sh_wpkh(self):
        """Native segwit single-sig"""
        path = "49h/1h/0h"
        fgp = sim.query("fingerprint").decode()
        xpub = sim.query(f"xpub m/{path}").decode()
        d1 = f"sh(wpkh([{fgp}/{path}]{xpub}/0/*))"
        d2 = f"sh(wpkh([{fgp}/{path}]{xpub}/1/*))"
        # combined with default derivation {0,1}/*
        d3 = f"sh(wpkh([{fgp}/{path}]{xpub}"+ "/{0,1}/*))"
        wname = wallet_prefix+"_sh_wpkh"
        res = sim.query("addwallet shwpkh&"+d3, [True])

        addr = Descriptor.from_string(d1).derive(5).address(NETWORKS['regtest'])
        # check it finds the wallet correctly
        res = sim.query(f"showaddr sh-wpkh m/{path}/0/5", [True])
        self.assertEqual(res.decode(), addr)

        self.sign_with_descriptor(wname, d1, d2)
コード例 #7
0
    def test_sighashes_legacy(self):
        """Native segwit single-sig"""
        path = "44h/1h/0h"
        fgp = sim.query("fingerprint").decode()
        xpub = sim.query(f"xpub m/{path}").decode()
        # legacy sighashes
        d1 = f"pkh([{fgp}/{path}]{xpub}/0/*)"
        d2 = f"pkh([{fgp}/{path}]{xpub}/1/*)"
        d3 = f"pkh([{fgp}/{path}]{xpub}"+ "/{0,1}/*)"
        wname = wallet_prefix+"_pkhsighash"

        res = sim.query("addwallet pkhsighsh&"+d3, [True])
        addr = Descriptor.from_string(d1).derive(5).address(NETWORKS['regtest'])
        # check it finds the wallet correctly
        res = sim.query(f"showaddr pkh m/{path}/0/5", [True])
        self.assertEqual(res.decode(), addr)

        self.sign_with_descriptor(wname, d1, d2, all_sighashes=True)
コード例 #8
0
    def test_legacy_sh(self):
        cosigner = "[12345678/41h/2h/0h]tpubDCUwbXdGiV5qFWMyaHBfdtDv1AZtUJmENrLMGEooEdyYka1Gk5FrBdoTp54EFWxopWi9H7udD4d8CxMNa2GUECRCodbBkd4eZfiQzbMXWU3"
        path = "49h/1h/0h/2h"
        fgp = sim.query("fingerprint").decode()
        xpub = sim.query(f"xpub m/{path}").decode()
        d1 = f"sh(sortedmulti(1,[{fgp}/{path}]{xpub}/0/*,{cosigner}/0/*))"
        d2 = f"sh(sortedmulti(1,[{fgp}/{path}]{xpub}/1/*,{cosigner}/1/*))"
        # combined with default derivation {0,1}/*
        d3 = f"sh(sortedmulti(1,[{fgp}/{path}]{xpub}/" + "{0,1}/*" + f",{cosigner}/"+"{0,1}/*))"
        res = sim.query("addwallet legsh&"+d3, [True])

        addr = Descriptor.from_string(d1).derive(5).address(NETWORKS['regtest'])
        # check it finds the wallet correctly
        sc = Descriptor.from_string(d1).derive(5).redeem_script().data.hex()
        res = sim.query(f"showaddr sh m/{path}/0/5 {sc}", [True])
        self.assertEqual(res.decode(), addr)

        wname = wallet_prefix+"_legsh"
        self.sign_with_descriptor(wname, d1, d2)
コード例 #9
0
    def test_no_derivation(self):
        """Default wallet without derivation path"""
        path = "84h/1h/0h"
        xpub = sim.query(f"xpub m/{path}").decode()
        d1 = f"wpkh({xpub}/0/*)"
        d2 = f"wpkh({xpub}/1/*)"
        wname = wallet_prefix+"_wpkh_noder"

        addr = Descriptor.from_string(d1).derive(5).address(NETWORKS['regtest'])

        self.sign_with_descriptor(wname, d1, d2)
コード例 #10
0
    def test_with_private(self):
        cosigner = "[12345678/41h/2h/0h]tprv8ffduPBLPgcNBZcXgCPo91WbmhXdpLKq8gtq7C6KnXbcqMPrj2NhSWp8WCjFarhBDi2TnPf7AcndKJZeF6Eq3uXXEbsbQZpk94cmrtopNH4"
        cosigner_public = "[12345678/41h/2h/0h]tpubDCMg3oDaY4J352eKZr4PYRAiLj3ZyfWjhzVcPi8dCoQ1fqedMRCHd1RzgLHXN7fbqMFCquaby2ETYKoVmjGLU7rdadZ2MeprqeHrJWHLKYn"
        cosigner2 = "cUHFVwhcD4jJnVQkuDw5MdhZQVf2t6qSF6miA7UDnDSyiBNSZ4st"
        cosigner2_public = "0307208358ae8ccce81c81ea7a89683ee854e1002e05be8df39cb0ca5ed44eac29"
        path = "49h/1h/0h/2h"
        fgp = sim.query("fingerprint").decode()
        xpub = sim.query(f"xpub m/{path}").decode()
        d1 = f"wsh(sortedmulti(3,[{fgp}/{path}]{xpub}/0/*,{cosigner_public}/0/*,"+f"{cosigner2_public}))"
        d2 = f"wsh(sortedmulti(3,[{fgp}/{path}]{xpub}/1/*,{cosigner_public}/1/*,"+f"{cosigner2_public}))"
        # combined with default derivation {0,1}/*
        d3 = f"wsh(sortedmulti(3,[{fgp}/{path}]{xpub}/" + "{0,1}/*" + f",{cosigner}/"+"{0,1}/*,"+f"{cosigner2}))"
        res = sim.query("addwallet wshpriv&"+d3, [True])

        addr = Descriptor.from_string(d1).derive(5).address(NETWORKS['regtest'])
        # check it finds the wallet correctly
        sc = Descriptor.from_string(d1).derive(5).witness_script().data.hex()
        res = sim.query(f"showaddr wsh m/{path}/0/5 {sc}", [True])
        self.assertEqual(res.decode(), addr)

        wname = wallet_prefix+"_wshprv"
        self.sign_with_descriptor(wname, d1, d2)
コード例 #11
0
    def test_add_wallet(self):
        # and(pk(A),after(100)) -> and_v(v:pk(A),after(100))
        desc = "wsh(and_v(v:pk([73c5da0a/44h/1h/0h]tpubDC5FSnBiZDMmhiuCmWAYsLwgLYrrT9rAqvTySfuCCrgsWz8wxMXUS9Tb9iVMvcRbvFcAHGkMD5Kx8koh4GquNGNTfohfk7pgjhaPCdXpoba),after(100)))"
        inv_desc = "wsh(and_v(v:pk([73c5da0a/44h/1h/0h]xpub6BhcvYN2qwQKRviMKKBTfRcK1RmCTmM7JHsg67r3rwvymhUEt8gPHhnkugQaQ7UN8M5FfhEUfyVuSaK5fQzfUpvAcCxN4bAT9jyySbPGsTs),after(100)))"
        addresses = [
            b"bitcoin:bcrt1qd7mtkvjmm7rlpgjjfv3902h6c749d7xuss0pr6garuq8q2qu9xas5qs39e?index=0",
            b"bitcoin:bcrt1qyrmdmuy0ml7m7fw3834lek6anrx20nrlmh7yvhsulu0dhxvgvkds4n9dq5?index=2"
        ]

        # shouldn't find addresses before adding a wallet
        for addr in addresses:
            res = sim.query(addr)
            self.assertTrue(b"error: Can't find wallet owning address" in res)

        res = sim.query(f"addwallet timelocked&{inv_desc})".encode())
        self.assertTrue(b"error" in res)

        res = sim.query(f"addwallet timelocked&{desc}".encode(), [True])

        # should find addresses after adding a wallet
        for addr in addresses:
            res = sim.query(addr, [None])
            self.assertFalse(b"error: Can't find wallet owning address" in res)
コード例 #12
0
    def test_miniscript(self):
        # and(pk(A),after(100)) -> and_v(v:pk(A),after(100))
        path = "49h/1h/0h/2h"
        fgp = sim.query("fingerprint").decode()
        xpub = sim.query(f"xpub m/{path}").decode()
        desc = f"wsh(and_v(v:pk([{fgp}/{path}]{xpub}"+"/{0,1}/*),after(10)))"
        res = sim.query("addwallet mini&"+desc, [True])

        wname = wallet_prefix+"_mini"
        d = Descriptor.from_string(desc)

        addr = d.derive(5).address(NETWORKS['regtest'])
        # check it finds the wallet correctly
        sc = d.derive(5).witness_script().data.hex()
        res = sim.query(f"showaddr wsh m/{path}/0/5 {sc}", [True])
        self.assertEqual(res.decode(), addr)

        d1 = d.derive(2, branch_index=0)
        d2 = d.derive(3, branch_index=1)
        # recv addr 2
        addr1 = d1.address(NETWORKS['regtest'])
        # change addr 3
        addr2 = d2.address(NETWORKS['regtest'])
        res = sim.query(f"bitcoin:{addr1}?index=2", [True])
        # check it's found
        self.assertFalse(b"Can't find wallet" in res)

        rpc.createwallet(wname, True, True)
        w = rpc.wallet(wname)
        res = w.importmulti([{
                "scriptPubKey": {"address": addr1},#d1.script_pubkey().data.hex(),
                # "witnessscript": d1.witness_script().data.hex(),
                # "pubkeys": [k.sec().hex() for k in d1.keys],
                "internal": False,
                "timestamp": "now",
                "watchonly": True,
            },{
                "scriptPubKey": {"address": addr2},#d2.script_pubkey().data.hex(),
                # "witnessscript": d2.witness_script().data.hex(),
                # "pubkeys": [k.sec().hex() for k in d2.keys],
                "internal": True,
                "timestamp": "now",
                "watchonly": True,
            }],{"rescan": False})
        self.assertTrue(all([k["success"] for k in res]))
        wdefault.sendtoaddress(addr1, 0.1)
        rpc.mine()
        unspent = w.listunspent()
        self.assertTrue(len(unspent) > 0)
        unspent = [{"txid": u["txid"], "vout": u["vout"]} for u in unspent[:1]]
        tx = w.createrawtransaction(unspent, [{wdefault.getnewaddress(): 0.002},{addr2: 0.09799}])
        psbt = PSBT.from_base64(w.converttopsbt(tx))
        # locktime magic :)
        psbt.tx.locktime = 11
        psbt.tx.vin[0].sequence = 10
        # fillinig psbt with data
        psbt.inputs[0].witness_script = d1.witness_script()
        pub = ec.PublicKey.parse(d1.keys[0].sec())
        psbt.inputs[0].bip32_derivations[pub] = DerivationPath(bytes.fromhex(fgp), bip32.parse_path(f"m/{path}")+[0,2])
        tx = w.gettransaction(unspent[0]["txid"])
        t = Transaction.from_string(tx["hex"])
        psbt.inputs[0].witness_utxo = t.vout[unspent[0]["vout"]]

        psbt.outputs[1].witness_script = d2.witness_script()
        pub2 = ec.PublicKey.parse(d2.keys[0].sec())
        psbt.outputs[1].bip32_derivations[pub2] = DerivationPath(bytes.fromhex(fgp), bip32.parse_path(f"m/{path}")+[1,3])

        unsigned = psbt.to_base64()
        # confirm signing
        signed = sim.query("sign "+unsigned, [True])
        stx = PSBT.from_base64(signed.decode())
        # signed tx
        t = psbt.tx
        # print(stx)
        t.vin[0].witness = Witness([stx.inputs[0].partial_sigs[pub], psbt.inputs[0].witness_script.data])
        # broadcast
        with self.assertRaises(Exception):
            res = rpc.sendrawtransaction(t.serialize().hex())
        rpc.mine(11)
        res = rpc.sendrawtransaction(t.serialize().hex())
        rpc.mine()
        self.assertEqual(len(bytes.fromhex(res)), 32)