|
| 1 | +# 16.3: Using Miniscript with Descriptors |
| 2 | + |
| 3 | +Miniscript and Policy are great for designing scripts outside of |
| 4 | +Bitcoin Core that can then be converted into Bitcoin Script and turned |
| 5 | +into addresses. |
| 6 | + |
| 7 | +Some wallets offer deeper usage of Miniscript, but Bitcoin Core |
| 8 | +integration currently remains limited: to date you can only use |
| 9 | +Miniscript with Bitcoin Core to create read-only P2WSH |
| 10 | +addresses. Doing so requires a combination of two things you've |
| 11 | +already learned: first you convert from Policy to Miniscript; then you |
| 12 | +create a descriptor to read into Bitcoin Core. (We call the result a |
| 13 | +"minidescriptor", but that's not a formal term.) |
| 14 | + |
| 15 | +## Create a P2WSH Minidescriptor |
| 16 | + |
| 17 | +Creating a minidescriptor for import into Bitcoin Core is a simple |
| 18 | +five-step process. |
| 19 | + |
| 20 | +1. **Create a Spending Policy** |
| 21 | + |
| 22 | + We're going to use our president & vice-president policy from |
| 23 | + previous chapters: |
| 24 | + |
| 25 | + ``` |
| 26 | + or(pk(president),thresh(2,pk(vp1),pk(vp2),pk(vp3))) |
| 27 | +
|
| 28 | + ``` |
| 29 | + |
| 30 | +2. **Convert the Policy to Miniscript** |
| 31 | + |
| 32 | + Compiling our Policy at [bitcoin.sipa.be](https://bitcoin.sipa.be/miniscript/) gives us our Miniscript: |
| 33 | + |
| 34 | + ``` |
| 35 | + or_d(pk(president),multi(2,vp1,vp2,vp3)) |
| 36 | +
|
| 37 | + ``` |
| 38 | + |
| 39 | +3. **Gather the Keys** |
| 40 | + |
| 41 | + To enter a minidescriptor into Bitcoin Core requires that you fill |
| 42 | + in the keys that should be used using base58 format. Since these |
| 43 | + Miniscripts are currently read-only, that means entering the xpubs, |
| 44 | + |
| 45 | + Various people involved in a Minidescriptor might have created |
| 46 | + their keys in a variety of ways. Our executives used `seedtool` and |
| 47 | + `keytool` from [chapter 10](10_0_Working_with_Secrets.md) to create |
| 48 | + their secrets as follows: |
| 49 | + |
| 50 | + ``` |
| 51 | + SEEDP=$(seedtool) |
| 52 | + KEYP=$(keytool --seed $SEEDP --account-derivation-path m/84h/1h/0h/0h --network testnet account-pub-key-base58) |
| 53 | + echo $KEYP |
| 54 | +
|
| 55 | + | tpubDFhGpPUEJaipdEeJtXZAUwb3Hz34hRCCqhvNgRwzrnbsGfXhCNEroYbGVHaVAyTAmJK4HXxLGCTXjP9HjwQRnG3oW7hCFY96JZkmo6kkCdt |
| 56 | +
|
| 57 | + SEEDVP1=$(seedtool) |
| 58 | + KEYVP1=$(keytool --seed $SEEDVP1 --account-derivation-path m/84h/1h/0h/0h --network testnet account-pub-key-base58) |
| 59 | + echo $KEYVP1 |
| 60 | +
|
| 61 | + |tpubDE1YvUwRqg2N2JfU5LKDGuuv3AM2d2CgMYQauAxgoWnGMVaHETz8n2Cdz3VGi9bbfFeY9dRrydeshyQzqPBLPwSEV8hRBZj5JMEqV3rTkc6 |
| 62 | +
|
| 63 | + SEEDVP2=$(seedtool) |
| 64 | + KEYVP2=$(keytool --seed $SEEDVP2 --account-derivation-path m/84h/1h/0h/0h --network testnet account-pub-key-base58) |
| 65 | + echo $KEYVP2 |
| 66 | +
|
| 67 | + | tpubDE8xY8eWp6CZcdeVQFYG7c2H12GeUpN5j5WLpGEYxurygx5HfjkcbN28vjMmTdYHRNvPauKRsKdgwuJ4hiyJ93gnXPadBoiZeUUJsQ2sP37 |
| 68 | +
|
| 69 | + SEEDVP3=$(seedtool) |
| 70 | + KEYVP3=$(keytool --seed $SEEDVP3 --account-derivation-path m/84h/1h/0h/0h --network testnet account-pub-key-base58) |
| 71 | + echo $KEYVP3 |
| 72 | + |
| 73 | + | tpubDE4kssfB4wqobfE3GWmYFkyV7giscXNG9HbXu2NykHoF1z9Tf4osozgPX4VZ8MnWxytKfeXAa89oZi9NUNauoLYcY51gFghUia34aAuj6sb |
| 74 | + ``` |
| 75 | + |
| 76 | +4. **Place the Keys in the Minidescriptor.** |
| 77 | + |
| 78 | + We gathered `84h/1h/0h/0h` keys. They're intended to support coins |
| 79 | + that are Segwit (`84h`), testnet (`1h`), first account (`0h`), |
| 80 | + non-change (`0h`). To allow for a range of addresses, we then |
| 81 | + supplement each key with a `/*` when we place it in our minscript. |
| 82 | + |
| 83 | + (⚠️ We would have liked to collect `84h/1h/0h` keys and then defined |
| 84 | + them as `0h/*`, which would be more normative use, but Bitcoin Core |
| 85 | + currently flags that as "duplicate keys" if you try, even though |
| 86 | + they're not.) |
| 87 | + |
| 88 | + ``` |
| 89 | + EXEC_MINID=$(echo "or_d(pk($KEYP/*),multi(2,$KEYVP1/*,$KEYVP2/*,$KEYVP3/*))") |
| 90 | + echo $EXEC_MINID |
| 91 | +
|
| 92 | + | or_d(pk(tpubDFhGpPUEJaipdEeJtXZAUwb3Hz34hRCCqhvNgRwzrnbsGfXhCNEroYbGVHaVAyTAmJK4HXxLGCTXjP9HjwQRnG3oW7hCFY96JZkmo6kkCdt/*),multi(2,tpubDE1YvUwRqg2N2JfU5LKDGuuv3AM2d2CgMYQauAxgoWnGMVaHETz8n2Cdz3VGi9bbfFeY9dRrydeshyQzqPBLPwSEV8hRBZj5JMEqV3rTkc6/*,tpubDE8xY8eWp6CZcdeVQFYG7c2H12GeUpN5j5WLpGEYxurygx5HfjkcbN28vjMmTdYHRNvPauKRsKdgwuJ4hiyJ93gnXPadBoiZeUUJsQ2sP37/*,tpubDE4kssfB4wqobfE3GWmYFkyV7giscXNG9HbXu2NykHoF1z9Tf4osozgPX4VZ8MnWxytKfeXAa89oZi9NUNauoLYcY51gFghUia34aAuj6sb/*)) |
| 93 | + ``` |
| 94 | + |
| 95 | +5. **Make a Wish** |
| 96 | + |
| 97 | + To turn our Miniscript into a descriptor (a minidescriptor) |
| 98 | + requires one more thing. It has to be defined with a normal |
| 99 | + descriptor function. |
| 100 | + |
| 101 | + Minidescriptors are currently only readable in Bitcoin Core as |
| 102 | + P2WSH addresses (not P2TR addresses). That requires a final step of |
| 103 | + embedding the Minidescriptor in `wsh(...)` to create a legal |
| 104 | + descriptor for Bitcoin Core to read. |
| 105 | + |
| 106 | + ``` |
| 107 | + EXEC_MINID=$(echo "wsh($EXEC_MINID)") |
| 108 | + echo $EXEC_MINID |
| 109 | +
|
| 110 | + | wsh(or_d(pk(tpubDFhGpPUEJaipdEeJtXZAUwb3Hz34hRCCqhvNgRwzrnbsGfXhCNEroYbGVHaVAyTAmJK4HXxLGCTXjP9HjwQRnG3oW7hCFY96JZkmo6kkCdt/*),multi(2,tpubDE1YvUwRqg2N2JfU5LKDGuuv3AM2d2CgMYQauAxgoWnGMVaHETz8n2Cdz3VGi9bbfFeY9dRrydeshyQzqPBLPwSEV8hRBZj5JMEqV3rTkc6/*,tpubDE8xY8eWp6CZcdeVQFYG7c2H12GeUpN5j5WLpGEYxurygx5HfjkcbN28vjMmTdYHRNvPauKRsKdgwuJ4hiyJ93gnXPadBoiZeUUJsQ2sP37/*,tpubDE4kssfB4wqobfE3GWmYFkyV7giscXNG9HbXu2NykHoF1z9Tf4osozgPX4VZ8MnWxytKfeXAa89oZi9NUNauoLYcY51gFghUia34aAuj6sb/*))) |
| 111 | + ``` |
| 112 | + |
| 113 | +## Import a P2WSH Minidescriptor |
| 114 | + |
| 115 | +The Minidescriptor that you've created should theoretically be |
| 116 | +readable anywhere that supports Miniscript descriptors. To incorporate |
| 117 | +it specifically into Bitcoin Core requires the following additional |
| 118 | +steps: |
| 119 | + |
| 120 | +6. **Add the Checksum** |
| 121 | + |
| 122 | + As you'll recall, you always need a checksum for Bitcoin Core |
| 123 | + descriptors. |
| 124 | + |
| 125 | + ``` |
| 126 | + EXEC_MINID_CS=$(bitcoin-cli getdescriptorinfo $EXEC_MINID | jq -r '.checksum') |
| 127 | + EXEC_MINID=$(echo $EXEC_MINID#$EXEC_MINID_CS) |
| 128 | + echo $EXEC_MINID |
| 129 | +
|
| 130 | + | wsh(or_d(pk(tpubDFhGpPUEJaipdEeJtXZAUwb3Hz34hRCCqhvNgRwzrnbsGfXhCNEroYbGVHaVAyTAmJK4HXxLGCTXjP9HjwQRnG3oW7hCFY96JZkmo6kkCdt/*),multi(2,tpubDE1YvUwRqg2N2JfU5LKDGuuv3AM2d2CgMYQauAxgoWnGMVaHETz8n2Cdz3VGi9bbfFeY9dRrydeshyQzqPBLPwSEV8hRBZj5JMEqV3rTkc6/*,tpubDE8xY8eWp6CZcdeVQFYG7c2H12GeUpN5j5WLpGEYxurygx5HfjkcbN28vjMmTdYHRNvPauKRsKdgwuJ4hiyJ93gnXPadBoiZeUUJsQ2sP37/*,tpubDE4kssfB4wqobfE3GWmYFkyV7giscXNG9HbXu2NykHoF1z9Tf4osozgPX4VZ8MnWxytKfeXAa89oZi9NUNauoLYcY51gFghUia34aAuj6sb/*)))#fhq2j999 |
| 131 | + ``` |
| 132 | + |
| 133 | +7. **Double-check Your Addresses** |
| 134 | + |
| 135 | + Before you import your Minidescriptor it's best practice to make |
| 136 | + sure you have the right one. You can check this by verifying the |
| 137 | + addresses it creates with the `deriveaddresses` command. |
| 138 | + |
| 139 | + ``` |
| 140 | + bitcoin-cli deriveaddresses $EXEC_MINID 2 |
| 141 | +
|
| 142 | + | [ |
| 143 | + | "tb1q5wj3hm4vask5zk2xzgdgw9slcpufml37yjnh0jhwf2c3sguuymhqsxc2gd", |
| 144 | + | "tb1qyxz7dv9859evxy5uutn3ueer978l73fw9ew0r2ajnj2lp5xltzpsrarv0q", |
| 145 | + | "tb1qy2s9l6jkhpnwfeyrsl88jj7e88a9k0dw0c8fyudeqv5lnqapm86q69zuue" |
| 146 | + | ] |
| 147 | + ``` |
| 148 | + |
| 149 | + Presumably you've got another version of this miniscripted account |
| 150 | + somewhere else, on the wallet you're spending from. You should |
| 151 | + check the range of addresses you derived with Bitcoin Core against |
| 152 | + the first few addresses on that other wallet and make sure they |
| 153 | + are the same. |
| 154 | + |
| 155 | +8. **Import Your Minidescriptor** |
| 156 | + |
| 157 | + Finally, you're ready to import your minidescriptor. You want to do |
| 158 | + so into a brand-new wallet: |
| 159 | + |
| 160 | + ``` |
| 161 | + bitcoin-cli -named createwallet wallet_name="watchmini" disable_private_keys=true blank=true |
| 162 | + ``` |
| 163 | + |
| 164 | + Like when we imported other watch-only addresses in |
| 165 | + [§7.1](07_1_Creating_Multisig_Public_Keys.md), we create the wallet |
| 166 | + without any private keys. |
| 167 | + |
| 168 | + Now you can import: |
| 169 | + |
| 170 | + ``` |
| 171 | + bitcoin-cli -rpcwallet=watchmini importdescriptors '''[{ "desc": "'$EXEC_MINID'", "timestamp": 1790329126 }]''' |
| 172 | + |
| 173 | + | [ |
| 174 | + | { |
| 175 | + | "success": true, |
| 176 | + | "warnings": [ |
| 177 | + | "Range not given, using default keypool range" |
| 178 | + | ] |
| 179 | + | } |
| 180 | + | ] |
| 181 | + ``` |
| 182 | + |
| 183 | + You now have a watch-only wallet that you can use to monitor a |
| 184 | + range of addresses that you defined through Miniscript! |
| 185 | + |
| 186 | +## Spend Your Funds |
| 187 | + |
| 188 | +Obviously, because this is a watch-only address, you can't spend the |
| 189 | +funds from Bitcoin Core. We've set it up this way because this is the |
| 190 | +only limited, trial functionality that Bitcoin Core has for |
| 191 | +minidescriptor importing at the time of this writing. |
| 192 | + |
| 193 | +As noted above, you should already be using this set of addresses |
| 194 | +somewhere else, in a wallet that you can actually spend from. But, |
| 195 | +that wallet may be offline; having a watch-only version will allow you |
| 196 | +to monitor its funds without exposing the private keys to the dangers |
| 197 | +of being on the net. |
| 198 | + |
| 199 | +## Summary: Using Miniscript with Descriptors |
| 200 | + |
| 201 | +Though you can use Bitcoin Scripts that you converted from Miniscript |
| 202 | +(or Policy) in Bitcoin Core, currently there's only limited ability to |
| 203 | +use Miniscript directly. |
| 204 | + |
| 205 | +The one thing you can do is read in a Miniscript descriptor built with |
| 206 | +public keys to create a read-only wallet. Doing so is a simple |
| 207 | +combination of the process you've already learned to convert Policy |
| 208 | +into Miniscript with the process you've already learned to read a |
| 209 | +descriptor into Bitcoin Core. |
| 210 | + |
| 211 | +## What's Next? |
| 212 | + |
| 213 | +Continue "Using Miniscript" with [§16.4: Using BDK](16_4_Using_BDK.md). |
0 commit comments