Title: what procedure to make hd descriptor multisig wallet, w/ bitcoin core 0.23 only Post by: CapLess2885 on December 19, 2022, 10:13:46 AM //////////////////////////////////////////////
Title: Re: what procedure to make hd descriptor multisig wallet, w/ bitcoin core 0.23 only Post by: nc50lc on December 19, 2022, 01:11:04 PM I am just curious about a clear detailled procedure for testing purposes, so please let us avoid warning posts or pro/con posts I think the provided steps are detailed enough since there're even examples that you can use to your test.The commands will also work in the GUI's console. Now, for the creation process: The problem is Bitcoin Core's GUI doesn't support the creation of such wallet natively so you'll have to find a way to safely create master private/public keys. One way is to create temporary wallets, use "listdescriptors true" and copy any descriptor's "xprv key" (pick any). Use listdescriptors false and copy the above's corresponding descriptor's "xpub key". Then proceed to "In Bitcoin Core" steps of the linked tutorial, use those extended keys in step 3. For the paper backup, just like above, Bitcoin Core doesn't support paper backup natively. But since it's a descriptor wallet, you can write each cosigner's 'receiving' and 'change' descriptors which can be imported to new wallets when needed. Follow step4-5 to import it to a new wallet, or backup the command in step 5 to have a ready-to-import (longer) string. - are there things to be cautious after (like updating the backup of the descriptors...)? Since all the child keys are based from the xprv key, you'll only need to backup once.Title: Re: what procedure to make hd descriptor multisig wallet, w/ bitcoin core 0.23 only Post by: nc50lc on December 20, 2022, 05:58:07 AM 1/ can I use sortedmulti instead of multi? Yes, that should work and will arrange the extended keys "lexicographically".1.a/ if yes, then I do not need to care of the order of xprv/xpub, and I can just systematically do xprv/xpub, right? The example in the other thread uses "multi" instead of "sortedmulti" so the user can manually put his original wallet's arrangement of keys. Quote from: CapLess2885 2/ in the other thread, you said "the derivation path differs per wallet, my example is based from BIP48". in my first try, I just copied the xprv/xpub and appended /0/* or /1/*, because when seeing your example, I thought you had voluntarily cut most of the derivation path and only let the /0/* part, but in fact it seems the full derivation path of your example is /0/*, right? When I tried without the full derivation path, at the end during the verification process of receiving addresses I got different receiving addresses for each cosigner. Then I tried to do the same process with the full derivation path /84/0/0/0/*, and the verification process showed the same addresses for each cosigner. Most of the path was cut because the extended keys to be imported are already at the "script type" level,as shown in BIP48 (link (https://github.com/bitcoin/bips/blob/master/bip-0048.mediawiki#path-levels)), the derivation path looks like this: m/purpose'/coin_type'/account'/script_type'/change/address_index Since his extended keys are at the script_type level, it should only be followed by /change/address_index (check "In BIP39 tool" steps to see how he got the xprv/xpub keys) You can provide the whole path if your xprv key is the master private key. I don't know why you got different address when not using the whole path but it may be due to an error when constructing the descriptor. Quote from: CapLess2885 3/ once they served their purpose, the first two temporary wallets can be then deleted and it is not requiered to be backed up right (as we have the xprv from the descriptors)? 3. Yes, after you created a backup of the cosigners' wallet.dat and the paper backups.4/ can you explain why any descriptor xprv type work? 5/ what does the sh mean in sh(wsh(multi? could wsh(multi work and how would it differ? 6/ I also tried sh(tr(multi but it does not work (higher level error if I recall) 4. xprv keys are simply a private key appended with a chain code, there's nothing to tell if it's a 'master private key' or an 'extended private key'. It's the descriptor that will tell your wallet which script type and derivation path to use. 5. sh is "Script Hash", wsh is "Witness Script Hash", it will work and will generate different address type which is P2WSH (bc1). sh is used in the example since OP's original wallet is P2SH-SegWit (as I recalled in his other thread) 6. I think P2SH-Taproot will not be implemented based from what I've read; (can't find the reference though) on the other hand, tr(multi isn't implemented. Title: Re: what procedure to make hd descriptor multisig wallet, w/ bitcoin core 0.23 only Post by: nc50lc on December 22, 2022, 06:29:42 AM listdescriptors true always show the master private key. listdesciptors true will show the private descriptors which has an xprv key Therefore it means the key is at m/ level, so I should write everything after m. Is this the logic? We should be able to tell based from the derivation path in the descriptor. In my example, I'm using it as an extended private/public key. I retried the process ten times with the full derivation path and each times the receiving addresses for each cosigners were the same. That's because of this (highlighted some parts):I have retried the process ten times without the full derivation path but only /0/* and each times the receiving addresses for each cosigners were different. But viewing your answer, it seems it should not be. So why that happen? Quote from: CapLess2885 22. switch to wallet1of2 In wallet cosigner1, xprv1/xpub1 has a derivation path of m/84'/0'/0'/0/* while23. importdescriptors "[{"desc":"wsh(sortedmulti(2,xprv1/84'/0'/0'/0/,xpub2/0/))#checksum1.0","timestamp":"now","active":true,"watching-only":false,"internal":false,"range":[0,999]}]" 24. importdescriptors "[{"desc":"wsh(sortedmulti(2,xprv1/84'/0'/0'/1/,xpub2/1/))#checksum1.1","timestamp":"now","active":true,"watching-only":false,"internal":true,"range":[0,999]}]" 25. switch to wallet2of2 26. importdescriptors "[{"desc":"wsh(sortedmulti(2,xprv2/84'/0'/0'/0/,xpub1/0/))#checksum2.0","timestamp":"now","active":true,"watching-only":false,"internal":false,"range":[0,999]}]" nn. importdescriptors "[{"desc":"wsh(sortedmulti(2,xprv2/84'/0'/0'/1/,xpub1/1/))#checksum2.1","timestamp":"now","active":true,"watching-only":false,"internal":true,"range":[0,999]}]" In wallet cosigner2, xprv1/xpub1 has a derivation path of m/0/* which will produce different child keys. The 'segwit sortedmulti' descriptors for those xprv/xpub key pairs should be, For cosigner1 (receiving): wsh(sortedmulti(2,"xprv1"/0/*,"xpub2"/0/*))) For cosigner1 (change): wsh(sortedmulti(2,"xprv1"/1/*,"xpub2"/1/*))) For cosigner2 (receiving): wsh(sortedmulti(2,"xprv2"/0/*,"xpub1"/0/*))) For cosigner2 (change): wsh(sortedmulti(2,"xprv2"/1/*,"xpub1"/1/*))) But if you want to use the xprv as the master private key to use the full derivation path and the "cut-off" path for the xpub (extended public key), you'll have to derive the master private key's "extended public key" at the correct level first before you can use the paths you've used in your descriptor. I used iancoleman's BIP39 tool to get the extended keys in the example below. (the master private key should pasted in "BIP32 Root Key" text box, then type custom derivation path, the extended keys will show below it) For example (RegTest - BIP48): Cosigner1: Master Private key: tprv8ZgxMBicQKsPeVVYWjJqFVveMsJYUHC2Z2MxQ4sbd3FnfaQeCB3ACHFUbhkDojKF5LanxLtEbSA eBppqYR9DSYMmiX8ckuc6V84p79ZiBm3 Derive the extended public key at m/48'/0'/0'/2' (script level for native segwit) Extended public key: tpubDF6UPFNY19vsBRAJ1XJ3GkatKf3NL8tQtJFfTqp8JXJe4v95A3pB2ppnxVproRB25uGzoJqSmkx ZCYEgLA1BEhRaTuvPFGQDrXbJYXZ5kv6 Cosigner2: Master Private key: tprv8ZgxMBicQKsPej5sbayjwxAYerQAdBw6zeexWj3juLP2buD5YuEExRDVUNBkzdDQJU7hizofNBm k7Fxe7zUDF3kYAoqTfp6wNa9mFceD5mD Derive the extended public key at m/48'/0'/0'/2' (script level for native segwit) Extended public key: tpubDEwuZxw5ri4w8CErxS1Sk2nJmn7WBcZCz6yCK6M3tTWCYTK6G3sZpbMMSdhxpK8Pykfsv5W3xEQ GK2bqGEEqzCuMcYhvWMwoSJHB9kcQZLb With that, you can now use your descriptor set-up: Import to cosigner1: Code: importdescriptors "[{\"desc\": \"wsh(sortedmulti(2,tprv8ZgxMBicQKsPeVVYWjJqFVveMsJYUHC2Z2MxQ4sbd3FnfaQeCB3ACHFUbhkDojKF5LanxLtEbSAeBppqYR9DSYMmiX8ckuc6V84p79ZiBm3/48'/0'/0'/2'/0/*,tpubDEwuZxw5ri4w8CErxS1Sk2nJmn7WBcZCz6yCK6M3tTWCYTK6G3sZpbMMSdhxpK8Pykfsv5W3xEQGK2bqGEEqzCuMcYhvWMwoSJHB9kcQZLb/0/*))#e9sdw8sm\",\"timestamp\": \"now\",\"active\": true,\"watching-only\": false,\"internal\": false,\"range\": [0,999]}]" Code: importdescriptors "[{\"desc\": \"wsh(sortedmulti(2,tprv8ZgxMBicQKsPej5sbayjwxAYerQAdBw6zeexWj3juLP2buD5YuEExRDVUNBkzdDQJU7hizofNBmk7Fxe7zUDF3kYAoqTfp6wNa9mFceD5mD/48'/0'/0'/2'/0/*,tpubDF6UPFNY19vsBRAJ1XJ3GkatKf3NL8tQtJFfTqp8JXJe4v95A3pB2ppnxVproRB25uGzoJqSmkxZCYEgLA1BEhRaTuvPFGQDrXbJYXZ5kv6/0/*))#2gew492h\",\"timestamp\": \"now\",\"active\": true,\"watching-only\": false,\"internal\": false,\"range\": [0,999]}]" (the extended pub key is already at "script_type" level [the 2' above] so the path to "address_index" should only be: extended_pub_key/0/*) Both wallets should generate the same address at first index: bcrt1qkhl5vjge39jv7c74frtq4pzxpa5jmguwz26vqatrm03uuhtjhtnq3dmftq Title: Re: what procedure to make hd descriptor multisig wallet, w/ bitcoin core 0.23 only Post by: nc50lc on December 22, 2022, 11:57:25 AM Quote listdesciptors true will show the private descriptors which has an xprv key but it's not indicated if it's the master private key or just an extended private key. What made me say that listdescriptors always output the master private key is this post by andrew chowWe should be able to tell based from the derivation path in the descriptor. I'll edit that part of my post accordingly. That is what I do when it works, but without having to derive the extended public key. I just use the listdescriptors output (xpriv and xpub) and... Theoretically, it shouldn't work since if xprv1/xpub1 are a pair and has different derivation paths in each descriptor,it works when I do "xprv1/84'/0'/0'/0/*,xpub2/0/*" and "xprv2/84'/0'/0'/0/*,xpub1/0/*", the receiving addresses are the same. it does not work I do "xprv1/0/*, xpub2/0/*" and "xprv2/0/*, xpub1/0/*", the receiving addresses are different. the child keys would be different. Example based from your description (Regtest): Cosigner1 extended key pair: Code: tprv8iQSEqLHrnFCHx8W7sdSsLvmkdXSAohWJzetBKmptFWFERtJXezarLCvnPDQoDreyc1jcgwafmmcBhGvEqrfBzr9hBS5czdxMmq7DiAN3aq Code: tprv8iFsRYtqiLPGEjD54nLrLd8CCkba2HNJQoNR2aJkUBhohy4Kdf3ye6jVGXDHnUtgKYumyEWJgQ2Wgc3U6mjhwV16XVmbjiyG3pYaqxMsK6t Code: importdescriptors "[{\"desc\": \"wsh(sortedmulti(2,tprv8iQSEqLHrnFCHx8W7sdSsLvmkdXSAohWJzetBKmptFWFERtJXezarLCvnPDQoDreyc1jcgwafmmcBhGvEqrfBzr9hBS5czdxMmq7DiAN3aq/84'/0'/0'/0/*,tpubDEwuZxw5ri4w8CErxS1Sk2nJmn7WBcZCz6yCK6M3tTWCYTK6G3sZpbMMSdhxpK8Pykfsv5W3xEQGK2bqGEEqzCuMcYhvWMwoSJHB9kcQZLb/0/*))#620d9yp0\",\"timestamp\": \"now\",\"active\": true,\"watching-only\": false,\"internal\": false,\"range\": [0,999]}]" Code: importdescriptors "[{\"desc\": \"wsh(sortedmulti(2,tprv8iFsRYtqiLPGEjD54nLrLd8CCkba2HNJQoNR2aJkUBhohy4Kdf3ye6jVGXDHnUtgKYumyEWJgQ2Wgc3U6mjhwV16XVmbjiyG3pYaqxMsK6t/84'/0'/0'/0/*,tpubDF6UPFNY19vsBRAJ1XJ3GkatKf3NL8tQtJFfTqp8JXJe4v95A3pB2ppnxVproRB25uGzoJqSmkxZCYEgLA1BEhRaTuvPFGQDrXbJYXZ5kv6/0/*))#ygmzfw0n\",\"timestamp\": \"now\",\"active\": true,\"watching-only\": false,\"internal\": false,\"range\": [0,999]}]" Cosigner2's first address is: bcrt1qyp3fd40qhdlvy0x8u7esurqqfhp8r7tthreye90puagtqwkgdcgqznkm65 I don't know how it worked at your end. On the other hand, using "xprv1"/0/*,"xpub2"/0/* works, for example (Regtest): Cosigner1 extended key pair: Code: tprv8iQSEqLHrnFCHx8W7sdSsLvmkdXSAohWJzetBKmptFWFERtJXezarLCvnPDQoDreyc1jcgwafmmcBhGvEqrfBzr9hBS5czdxMmq7DiAN3aq Code: tprv8iFsRYtqiLPGEjD54nLrLd8CCkba2HNJQoNR2aJkUBhohy4Kdf3ye6jVGXDHnUtgKYumyEWJgQ2Wgc3U6mjhwV16XVmbjiyG3pYaqxMsK6t Code: importdescriptors "[{\"desc\": \"wsh(sortedmulti(2,tprv8iQSEqLHrnFCHx8W7sdSsLvmkdXSAohWJzetBKmptFWFERtJXezarLCvnPDQoDreyc1jcgwafmmcBhGvEqrfBzr9hBS5czdxMmq7DiAN3aq/0/*,tpubDEwuZxw5ri4w8CErxS1Sk2nJmn7WBcZCz6yCK6M3tTWCYTK6G3sZpbMMSdhxpK8Pykfsv5W3xEQGK2bqGEEqzCuMcYhvWMwoSJHB9kcQZLb/0/*))#5269m2an\",\"timestamp\": \"now\",\"active\": true,\"watching-only\": false,\"internal\": false,\"range\": [0,999]}]" Code: importdescriptors "[{\"desc\": \"wsh(sortedmulti(2,tprv8iFsRYtqiLPGEjD54nLrLd8CCkba2HNJQoNR2aJkUBhohy4Kdf3ye6jVGXDHnUtgKYumyEWJgQ2Wgc3U6mjhwV16XVmbjiyG3pYaqxMsK6t/0/*,tpubDF6UPFNY19vsBRAJ1XJ3GkatKf3NL8tQtJFfTqp8JXJe4v95A3pB2ppnxVproRB25uGzoJqSmkxZCYEgLA1BEhRaTuvPFGQDrXbJYXZ5kv6/0/*))#la8dlq5x\",\"timestamp\": \"now\",\"active\": true,\"watching-only\": false,\"internal\": false,\"range\": [0,999]}]" Title: Re: what procedure to make hd descriptor multisig wallet, w/ bitcoin core 0.23 only Post by: nc50lc on December 22, 2022, 06:33:12 PM Sorry, I think I found the issue and it's embarrassingly simple.
It works at your end because your xprv and xpub aren't a pair but actually the master private key and extended private key. That's because listdescriptor true shows the master private key while listdescriptors shows the extended public key. So using the full path for the xprv and the cut-off path for the xpub key works just like in my other example that's similar to yours. The confusion is my fault for not testing the my suggested source of xprv and xpub keys. My xprv and xpub keys on the other hand are pairs. Title: Re: what procedure to make hd descriptor multisig wallet, w/ bitcoin core 0.23 only Post by: nc50lc on December 23, 2022, 04:25:12 AM so to conclude all of this... is there a better way between masterxprv/derivation + xpub/0 and xprv/0/*+xpub/0/* ? Unfortunately, there's no other option in Bitcoin Core to make HD MultiSig setup other utilizing descriptors.are there any differences other than it is simpler to just use a simple xprv+xpub (no need to note the derivation path)? And descriptors require derivation path. The other options createmultisig/addmultisig are for single multisig address. There's currently also no way to generate MultiSig wallet using createwallet rpc, either. Perhaps in future releases. |