Skip to content

Commit 19a354b

Browse files
committed
Output a descriptor in createmultisig and addmultisigaddress
1 parent 3e1bf71 commit 19a354b

File tree

5 files changed

+33
-1
lines changed

5 files changed

+33
-1
lines changed

doc/descriptors.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ Supporting RPCs are:
1717
(`regtest` only, since v0.19).
1818
- `utxoupdatepsbt` takes as input descriptors to add information to the psbt
1919
(since v0.19).
20+
- `createmultisig` and `addmultisigaddress` return descriptors as well (since v0.20)
2021

2122
This document describes the language. For the specifics on usage, see the RPC
2223
documentation for the functions mentioned above.

src/rpc/misc.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ static UniValue createmultisig(const JSONRPCRequest& request)
8383
"{\n"
8484
" \"address\":\"multisigaddress\", (string) The value of the new multisig address.\n"
8585
" \"redeemScript\":\"script\" (string) The string value of the hex-encoded redemption script.\n"
86+
" \"descriptor\":\"descriptor\" (string) The descriptor for this multisig\n"
8687
"}\n"
8788
},
8889
RPCExamples{
@@ -119,9 +120,13 @@ static UniValue createmultisig(const JSONRPCRequest& request)
119120
CScript inner;
120121
const CTxDestination dest = AddAndGetMultisigDestination(required, pubkeys, output_type, keystore, inner);
121122

123+
// Make the descriptor
124+
std::unique_ptr<Descriptor> descriptor = InferDescriptor(GetScriptForDestination(dest), keystore);
125+
122126
UniValue result(UniValue::VOBJ);
123127
result.pushKV("address", EncodeDestination(dest));
124128
result.pushKV("redeemScript", HexStr(inner.begin(), inner.end()));
129+
result.pushKV("descriptor", descriptor->ToString());
125130

126131
return result;
127132
}

src/wallet/rpcwallet.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -974,6 +974,7 @@ static UniValue addmultisigaddress(const JSONRPCRequest& request)
974974
"{\n"
975975
" \"address\":\"multisigaddress\", (string) The value of the new multisig address.\n"
976976
" \"redeemScript\":\"script\" (string) The string value of the hex-encoded redemption script.\n"
977+
" \"descriptor\":\"descriptor\" (string) The descriptor for this multisig\n"
977978
"}\n"
978979
},
979980
RPCExamples{
@@ -1018,9 +1019,13 @@ static UniValue addmultisigaddress(const JSONRPCRequest& request)
10181019
CTxDestination dest = AddAndGetMultisigDestination(required, pubkeys, output_type, spk_man, inner);
10191020
pwallet->SetAddressBook(dest, label, "send");
10201021

1022+
// Make the descriptor
1023+
std::unique_ptr<Descriptor> descriptor = InferDescriptor(GetScriptForDestination(dest), spk_man);
1024+
10211025
UniValue result(UniValue::VOBJ);
10221026
result.pushKV("address", EncodeDestination(dest));
10231027
result.pushKV("redeemScript", HexStr(inner.begin(), inner.end()));
1028+
result.pushKV("descriptor", descriptor->ToString());
10241029
return result;
10251030
}
10261031

test/functional/rpc_createmultisig.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
55
"""Test multisig RPCs"""
66

7-
from test_framework.descriptors import descsum_create
7+
from test_framework.descriptors import descsum_create, drop_origins
88
from test_framework.test_framework import BitcoinTestFramework
99
from test_framework.util import (
1010
assert_raises_rpc_error,
@@ -116,16 +116,28 @@ def checkbalances(self):
116116
def do_multisig(self):
117117
node0, node1, node2 = self.nodes
118118

119+
# Construct the expected descriptor
120+
desc = 'multi({},{})'.format(self.nsigs, ','.join(self.pub))
121+
if self.output_type == 'legacy':
122+
desc = 'sh({})'.format(desc)
123+
elif self.output_type == 'p2sh-segwit':
124+
desc = 'sh(wsh({}))'.format(desc)
125+
elif self.output_type == 'bech32':
126+
desc = 'wsh({})'.format(desc)
127+
desc = descsum_create(desc)
128+
119129
msig = node2.createmultisig(self.nsigs, self.pub, self.output_type)
120130
madd = msig["address"]
121131
mredeem = msig["redeemScript"]
132+
assert_equal(desc, msig['descriptor'])
122133
if self.output_type == 'bech32':
123134
assert madd[0:4] == "bcrt" # actually a bech32 address
124135

125136
# compare against addmultisigaddress
126137
msigw = node1.addmultisigaddress(self.nsigs, self.pub, None, self.output_type)
127138
maddw = msigw["address"]
128139
mredeemw = msigw["redeemScript"]
140+
assert_equal(desc, drop_origins(msigw['descriptor']))
129141
# addmultisigiaddress and createmultisig work the same
130142
assert maddw == madd
131143
assert mredeemw == mredeem

test/functional/test_framework/descriptors.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
55
"""Utility functions related to output descriptors"""
66

7+
import re
8+
79
INPUT_CHARSET = "0123456789()[],'/*abcdefgh@:$%{}IJKLMNOPQRSTUVWXYZ&+-.;<=>?!^_|~ijklmnopqrstuvwxyzABCDEFGH`#\"\\ "
810
CHECKSUM_CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"
911
GENERATOR = [0xf5dee51989, 0xa9fdca3312, 0x1bab10e32d, 0x3706b1677a, 0x644d626ffd]
@@ -53,3 +55,10 @@ def descsum_check(s, require=True):
5355
return False
5456
symbols = descsum_expand(s[:-9]) + [CHECKSUM_CHARSET.find(x) for x in s[-8:]]
5557
return descsum_polymod(symbols) == 1
58+
59+
def drop_origins(s):
60+
'''Drop the key origins from a descriptor'''
61+
desc = re.sub(r'\[.+?\]', '', s)
62+
if '#' in s:
63+
desc = desc[:desc.index('#')]
64+
return descsum_create(desc)

0 commit comments

Comments
 (0)