Let's say i have two xpubs, derived at m/1'/2'/3'/0 from a master xpub. I'd like to create a descriptor describing a multisig between those 2 keys.
I create a descriptor wallet
$ bcreg1 -named createwallet wallet_name=repro disable_private_keys=true descriptors=true
{
"name": "repro",
"warning": ""
}
Since i won't compute the checksum by hand i use the hack of getting it from getdescriptorinfo
$ bcreg1 getdescriptorinfo "wsh(multi(2,[0a0a0a0a/1'/2'/3'/0]tpubD6NzVbkrYhZ4WkU5UCcpShsnkYoYPSH9Lor6Kg7J6ytgCjcrpZKtpLPT4NtWLoVirjiWPhgupH1V1UkKaTJoFCRPbcZwMN6kxepTUzKg6mM/*,[bbbbbbbb/1'/2'/3'/0]tpubD6NzVbkrYhZ4Xm62aaUb6DiTMqnnbQNKQsBddsiHwx2Q2KaqYApSCizhyZcEaCRSvr5QSZKuF53pJ6ZQcRzFFDJ6HaKAkpdJAfZt8h1ZzDz/*))"
{
"descriptor": "wsh(multi(2,[0a0a0a0a/1'/2'/3'/0]tpubD6NzVbkrYhZ4WkU5UCcpShsnkYoYPSH9Lor6Kg7J6ytgCjcrpZKtpLPT4NtWLoVirjiWPhgupH1V1UkKaTJoFCRPbcZwMN6kxepTUzKg6mM/*,[bbbbbbbb/1'/2'/3'/0]tpubD6NzVbkrYhZ4Xm62aaUb6DiTMqnnbQNKQsBddsiHwx2Q2KaqYApSCizhyZcEaCRSvr5QSZKuF53pJ6ZQcRzFFDJ6HaKAkpdJAfZt8h1ZzDz/*))#hs0kuwwv",
"checksum": "hs0kuwwv",
"isrange": true,
"issolvable": true,
"hasprivatekeys": false
}
Now i use the output of getdescriptorinfo to import the descriptor and...
$ bcreg1 -rpcwallet=repro importdescriptors '[{"desc":"wsh(multi(2,[0a0a0a0a/1'/2'/3'/0]tpubD6NzVbkrYhZ4WkU5UCcpShsnkYoYPSH9Lor6Kg7J6ytgCjcrpZKtpLPT4NtWLoVirjiWPhgupH1V1UkKaTJoFCRPbcZwMN6kxepTUzKg6mM/*,[bbbbbbbb/1'/2'/3'/0]tpubD6NzVbkrYhZ4Xm62aaUb6DiTMqnnbQNKQsBddsiHwx2Q2KaqYApSCizhyZcEaCRSvr5QSZKuF53pJ6ZQcRzFFDJ6HaKAkpdJAfZt8h1ZzDz/*))#hs0kuwwv","timestamp":"now"}]'
[
{
"success": false,
"error": {
"code": -5,
"message": "Provided checksum 'hs0kuwwv' does not match computed checksum 'rgsu3znf'"
}
}
]
Hmm. Turns out the checksum getdescriptorinfo gave me is invalid (both in the "descriptor" and "checksum" fields). I remember some discussions around canonicalization and the h vs ' notation for hardened paths, so i try by using h instead.
$ bcreg1 getdescriptorinfo "wsh(multi(2,[0a0a0a0a/1h/2h/3h/0]tpubD6NzVbkrYhZ4WkU5UCcpShsnkYoYPSH9Lor6Kg7J6ytgCjcrpZKtpLPT4NtWLoVirjiWPhgupH1V1UkKaTJoFCRPbcZwMN6kxepTUzKg6mM/*,[bbbbbbbb/1h/2h/3h/0]tpubD6NzVbkrYhZ4Xm62aaUb6DiTMqnnbQNKQsBddsiHwx2Q2KaqYApSCizhyZcEaCRSvr5QSZKuF53pJ6ZQcRzFFDJ6HaKAkpdJAfZt8h1ZzDz/*))"
{
"descriptor": "wsh(multi(2,[0a0a0a0a/1'/2'/3'/0]tpubD6NzVbkrYhZ4WkU5UCcpShsnkYoYPSH9Lor6Kg7J6ytgCjcrpZKtpLPT4NtWLoVirjiWPhgupH1V1UkKaTJoFCRPbcZwMN6kxepTUzKg6mM/*,[bbbbbbbb/1'/2'/3'/0]tpubD6NzVbkrYhZ4Xm62aaUb6DiTMqnnbQNKQsBddsiHwx2Q2KaqYApSCizhyZcEaCRSvr5QSZKuF53pJ6ZQcRzFFDJ6HaKAkpdJAfZt8h1ZzDz/*))#hs0kuwwv",
"checksum": "6nuh6ujc",
"isrange": true,
"issolvable": true,
"hasprivatekeys": false
}
It outputs the same invalid descriptor in the "descriptor" field. Fortunately the checksum in "checksum" is actually valid, so i can use that in importdescriptors.
Maybe worth mentioning, before trying on latest master i had an additional issue with 22.0 where getdescriptorinfo would literally remove the hardened paths from the origin info:
$ bc getdescriptorinfo 'wsh(sortedmulti(2,[f4d84203/48'/0'/0']xpub6BqGLdDLrAeSfoaxcU4VPLrLjWnVAdTcE1jFaocxupbqpyU6tdUA6nZoU17RrYQaGxpjWh7eLempM6W8d6C4p5siF8rWvgvwnASKyzKn14S/0/*,[ff620a62/48'/0'/0']xpub6C7cPJJsmrM6hQuqX2DEdqn38VF2csDeC5BmQbSzpga4EP64V211hYSCSStkFKnELchieG2WKMckrKRdHrUjeaCbRszHJJ7nP4E68rPViPE/0/*))'
{
"descriptor": "wsh(sortedmulti(2,[f4d84203/48/0/0]xpub6BqGLdDLrAeSfoaxcU4VPLrLjWnVAdTcE1jFaocxupbqpyU6tdUA6nZoU17RrYQaGxpjWh7eLempM6W8d6C4p5siF8rWvgvwnASKyzKn14S/0/*,[ff620a62/48/0/0]xpub6C7cPJJsmrM6hQuqX2DEdqn38VF2csDeC5BmQbSzpga4EP64V211hYSCSStkFKnELchieG2WKMckrKRdHrUjeaCbRszHJJ7nP4E68rPViPE/0/*))#kvvtf4uz",
"checksum": "kvvtf4uz",
"isrange": true,
"issolvable": true,
"hasprivatekeys": false
}
So maybe the bad checksum above was the checksum without the hardened paths?
$ bcreg1 getdescriptorinfo "wsh(multi(2,[0a0a0a0a/1/2/3/0]tpubD6NzVbkrYhZ4WkU5UCcpShsnkYoYPSH9Lor6Kg7J6ytgCjcrpZKtpLPT4NtWLoVirjiWPhgupH1V1UkKaTJoFCRPbcZwMN6kxepTUzKg6mM/*,[bbbbbbbb/1/2/3/0]tpubD6NzVbkrYhZ4Xm62aaUb6DiTMqnnbQNKQsBddsiHwx2Q2KaqYApSCizhyZcEaCRSvr5QSZKuF53pJ6ZQcRzFFDJ6HaKAkpdJAfZt8h1ZzDz/*))"
{
"descriptor": "wsh(multi(2,[0a0a0a0a/1/2/3/0]tpubD6NzVbkrYhZ4WkU5UCcpShsnkYoYPSH9Lor6Kg7J6ytgCjcrpZKtpLPT4NtWLoVirjiWPhgupH1V1UkKaTJoFCRPbcZwMN6kxepTUzKg6mM/*,[bbbbbbbb/1/2/3/0]tpubD6NzVbkrYhZ4Xm62aaUb6DiTMqnnbQNKQsBddsiHwx2Q2KaqYApSCizhyZcEaCRSvr5QSZKuF53pJ6ZQcRzFFDJ6HaKAkpdJAfZt8h1ZzDz/*))#rgsu3znf",
"checksum": "rgsu3znf",
"isrange": true,
"issolvable": true,
"hasprivatekeys": false
}
Bingo!