Skip to content

Commit d26e7c6

Browse files
committed
feat<node>: add descriptor support in createmultisig rpc
1 parent 2e4f450 commit d26e7c6

File tree

3 files changed

+185
-15
lines changed

3 files changed

+185
-15
lines changed

lib/descriptor/abstractdescriptor.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ class AbstractDescriptor {
241241
* @returns {Script[]}
242242
*/
243243

244-
generateScripts(pos) {
244+
generateScripts(pos = 0) {
245245
const pubkeys = [];
246246
const subscripts = [];
247247

@@ -274,7 +274,7 @@ class AbstractDescriptor {
274274
* @returns {Address[]}
275275
*/
276276

277-
getAddresses(pos) {
277+
getAddresses(pos = 0) {
278278
const scripts = this.generateScripts(pos);
279279
const addresses = [];
280280

lib/node/rpc.js

Lines changed: 47 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,15 @@ const TX = require('../primitives/tx');
3535
const consensus = require('../protocol/consensus');
3636
const pkg = require('../pkg');
3737
const {filters} = require('../blockstore/common');
38-
const {createChecksum} = require('../descriptor/common');
38+
const MultisigDescriptor = require('../descriptor/type/multisig');
39+
const SHDescriptor = require('../descriptor/type/sh');
40+
const WSHDescriptor = require('../descriptor/type/wsh');
3941
const {parse} = require('../descriptor/parser');
4042
const RPCBase = bweb.RPC;
4143
const RPCError = bweb.RPCError;
44+
const {
45+
createChecksum, outputTypes, scriptContext
46+
} = require('../descriptor/common');
4247

4348
/*
4449
* Constants
@@ -2050,17 +2055,28 @@ class RPC extends RPCBase {
20502055
*/
20512056

20522057
async createMultisig(args, help) {
2053-
if (help || args.length < 2 || args.length > 2) {
2058+
if (help || args.length < 2 || args.length > 3) {
20542059
throw new RPCError(errs.MISC_ERROR,
2055-
'createmultisig nrequired ["key",...]');
2060+
'createmultisig nrequired ["key",...] (address_type)');
20562061
}
20572062

20582063
const valid = new Validator(args);
20592064
const keys = valid.array(1, []);
2065+
let outputType = valid.str(2);
2066+
2067+
if (outputType === null) {
2068+
outputType = outputTypes.LEGACY;
2069+
}
2070+
2071+
assert(
2072+
Object.values(outputTypes).includes(outputType),
2073+
`Unknown address type '${outputType}'.`
2074+
);
2075+
20602076
const m = valid.u32(0, 0);
20612077
const n = keys.length;
20622078

2063-
if (m < 1 || n < m || n > 16)
2079+
if (m < 1 || n < m || n > 20)
20642080
throw new RPCError(errs.INVALID_PARAMETER, 'Invalid m and n values.');
20652081

20662082
const items = new Validator(keys);
@@ -2074,21 +2090,39 @@ class RPC extends RPCBase {
20742090
if (!secp256k1.publicKeyVerify(key))
20752091
throw new RPCError(errs.INVALID_ADDRESS_OR_KEY, 'Invalid key.');
20762092

2077-
keys[i] = key;
2093+
keys[i] = items.str(i, '');
20782094
}
20792095

2080-
const script = Script.fromMultisig(m, n, keys, true, false);
2096+
const {P2SH, P2WSH} = scriptContext;
2097+
const context = outputType === outputTypes.LEGACY ? P2SH : P2WSH;
20812098

2082-
if (script.getSize() > consensus.MAX_SCRIPT_PUSH) {
2083-
throw new RPCError(errs.VERIFY_ERROR,
2084-
'Redeem script exceeds size limit.');
2085-
}
2099+
const subdesc = MultisigDescriptor.fromString(
2100+
`multi(${m},${keys.join(',')})`, this.network, context
2101+
);
20862102

2087-
const addr = script.getAddress();
2103+
let descriptor;
2104+
2105+
const options = {
2106+
subdescriptors: [subdesc], network: this.network
2107+
};
2108+
2109+
switch (outputType) {
2110+
case outputTypes.LEGACY:
2111+
descriptor = SHDescriptor.fromOptions(options);
2112+
break;
2113+
case outputTypes.BECH32:
2114+
descriptor = WSHDescriptor.fromOptions(options);
2115+
break;
2116+
case outputTypes.P2SH_SEGWIT: {
2117+
options.subdescriptors = [WSHDescriptor.fromOptions(options)];
2118+
descriptor = SHDescriptor.fromOptions(options);
2119+
}
2120+
}
20882121

20892122
return {
2090-
address: addr.toString(this.network),
2091-
redeemScript: script.toJSON()
2123+
address: descriptor.getAddresses()[0],
2124+
redeemScript: subdesc.generateScripts()[0].toJSON(),
2125+
descriptor: descriptor.toString()
20922126
};
20932127
}
20942128

test/node-rpc-test.js

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,142 @@ describe('RPC', function() {
234234
}
235235
});
236236

237+
it('should rpc createmultisig', async () => {
238+
const data = [
239+
{
240+
'm': 4,
241+
'keys': [
242+
'02f293c4d026a536a082453f8327f305ae0a0c59350b396205e15fbec2af67390b',
243+
'03d7b6a7e972f6e1a532f9f49a7cc35055a0ffd7cec5f81728f6a3fdf4dad93672',
244+
'021f360d51b8eb43422fe942c837ad16e36bab87c5f7567609de9a38e205fb51ed',
245+
'03a778eaee9cc18a4e5e02a78f403082d4e6f3a9c0d9edaea20b9ad86089de7fc9',
246+
'02a3c95e41e8272c6842df8c9da492ef5e03bbc4ca17c22ce1f88570e716e187db',
247+
'032e1d465bc5cdea674337934fb861d097dd7ab20289e4d41de14a6cafcd61d30a',
248+
'0370fd35da88778a805ce9acc88c0020e3b14cacaa30f99d829207e1896d782ea1',
249+
'03878a4b831af4fee069964448ccca999071633fcc751d296e8c5325167274febf',
250+
'0248f8621596029568070dda40bc1e3ace78df320b5ebf0d6a431536e9af3ec894',
251+
'03f757260835b7e439b244a9b10f5645966d7dcff9d2648c400a0d6827f4a64ac4',
252+
'023b3972554e123985b6c3d8575e6fd3384f59a58ef91e0d39ba5905dad49e7372',
253+
'02e32652928f21764e02822d39ffd1075c428e372a06fe7247023d5b60f1d01596',
254+
'020e002818c48b1d1766f6196e09db90f51e155bbd49be0ad743d1fa6b7e8efcae',
255+
'03725d482f0c77f4feb1ecbea28f036b30889f462222002e88aa8f8346dce94474'
256+
],
257+
'address_type': 'p2sh-segwit',
258+
'result': {
259+
'address': '2N5YHZJYNqXqCwiX2FTQ9ZgwCoW4qksY2CE',
260+
'redeemScript':
261+
'542102f293c4d026a536a082453f8327f305ae0a0c59350b396205e15fbec2af67390b2103d7b6a7e972f6e1a532f9f49a7cc35055a0ffd7cec5f81728f6a3fdf4dad9367221021f360d51b8eb43422fe942c837ad16e36bab87c5f7567609de9a38e205fb51ed2103a778eaee9cc18a4e5e02a78f403082d4e6f3a9c0d9edaea20b9ad86089de7fc92102a3c95e41e8272c6842df8c9da492ef5e03bbc4ca17c22ce1f88570e716e187db21032e1d465bc5cdea674337934fb861d097dd7ab20289e4d41de14a6cafcd61d30a210370fd35da88778a805ce9acc88c0020e3b14cacaa30f99d829207e1896d782ea12103878a4b831af4fee069964448ccca999071633fcc751d296e8c5325167274febf210248f8621596029568070dda40bc1e3ace78df320b5ebf0d6a431536e9af3ec8942103f757260835b7e439b244a9b10f5645966d7dcff9d2648c400a0d6827f4a64ac421023b3972554e123985b6c3d8575e6fd3384f59a58ef91e0d39ba5905dad49e73722102e32652928f21764e02822d39ffd1075c428e372a06fe7247023d5b60f1d0159621020e002818c48b1d1766f6196e09db90f51e155bbd49be0ad743d1fa6b7e8efcae2103725d482f0c77f4feb1ecbea28f036b30889f462222002e88aa8f8346dce944745eae',
262+
'descriptor':
263+
'sh(wsh(multi(4,02f293c4d026a536a082453f8327f305ae0a0c59350b396205e15fbec2af67390b,03d7b6a7e972f6e1a532f9f49a7cc35055a0ffd7cec5f81728f6a3fdf4dad93672,021f360d51b8eb43422fe942c837ad16e36bab87c5f7567609de9a38e205fb51ed,03a778eaee9cc18a4e5e02a78f403082d4e6f3a9c0d9edaea20b9ad86089de7fc9,02a3c95e41e8272c6842df8c9da492ef5e03bbc4ca17c22ce1f88570e716e187db,032e1d465bc5cdea674337934fb861d097dd7ab20289e4d41de14a6cafcd61d30a,0370fd35da88778a805ce9acc88c0020e3b14cacaa30f99d829207e1896d782ea1,03878a4b831af4fee069964448ccca999071633fcc751d296e8c5325167274febf,0248f8621596029568070dda40bc1e3ace78df320b5ebf0d6a431536e9af3ec894,03f757260835b7e439b244a9b10f5645966d7dcff9d2648c400a0d6827f4a64ac4,023b3972554e123985b6c3d8575e6fd3384f59a58ef91e0d39ba5905dad49e7372,02e32652928f21764e02822d39ffd1075c428e372a06fe7247023d5b60f1d01596,020e002818c48b1d1766f6196e09db90f51e155bbd49be0ad743d1fa6b7e8efcae,03725d482f0c77f4feb1ecbea28f036b30889f462222002e88aa8f8346dce94474)))#a880m646'
264+
}
265+
},
266+
{
267+
'm': 4,
268+
'keys': [
269+
'02f293c4d026a536a082453f8327f305ae0a0c59350b396205e15fbec2af67390b',
270+
'03d7b6a7e972f6e1a532f9f49a7cc35055a0ffd7cec5f81728f6a3fdf4dad93672',
271+
'021f360d51b8eb43422fe942c837ad16e36bab87c5f7567609de9a38e205fb51ed',
272+
'03a778eaee9cc18a4e5e02a78f403082d4e6f3a9c0d9edaea20b9ad86089de7fc9',
273+
'02a3c95e41e8272c6842df8c9da492ef5e03bbc4ca17c22ce1f88570e716e187db',
274+
'032e1d465bc5cdea674337934fb861d097dd7ab20289e4d41de14a6cafcd61d30a',
275+
'0370fd35da88778a805ce9acc88c0020e3b14cacaa30f99d829207e1896d782ea1',
276+
'03878a4b831af4fee069964448ccca999071633fcc751d296e8c5325167274febf',
277+
'0248f8621596029568070dda40bc1e3ace78df320b5ebf0d6a431536e9af3ec894',
278+
'03f757260835b7e439b244a9b10f5645966d7dcff9d2648c400a0d6827f4a64ac4',
279+
'023b3972554e123985b6c3d8575e6fd3384f59a58ef91e0d39ba5905dad49e7372',
280+
'02e32652928f21764e02822d39ffd1075c428e372a06fe7247023d5b60f1d01596',
281+
'020e002818c48b1d1766f6196e09db90f51e155bbd49be0ad743d1fa6b7e8efcae',
282+
'03725d482f0c77f4feb1ecbea28f036b30889f462222002e88aa8f8346dce94474'
283+
],
284+
'address_type': 'bech32',
285+
'result': {
286+
'address':
287+
'bcrt1qwn0zfduv4tu2jga3dl4a3r87dpk3da6ke5t2uhy306ynlrpg5eas47sw6n',
288+
'redeemScript':
289+
'542102f293c4d026a536a082453f8327f305ae0a0c59350b396205e15fbec2af67390b2103d7b6a7e972f6e1a532f9f49a7cc35055a0ffd7cec5f81728f6a3fdf4dad9367221021f360d51b8eb43422fe942c837ad16e36bab87c5f7567609de9a38e205fb51ed2103a778eaee9cc18a4e5e02a78f403082d4e6f3a9c0d9edaea20b9ad86089de7fc92102a3c95e41e8272c6842df8c9da492ef5e03bbc4ca17c22ce1f88570e716e187db21032e1d465bc5cdea674337934fb861d097dd7ab20289e4d41de14a6cafcd61d30a210370fd35da88778a805ce9acc88c0020e3b14cacaa30f99d829207e1896d782ea12103878a4b831af4fee069964448ccca999071633fcc751d296e8c5325167274febf210248f8621596029568070dda40bc1e3ace78df320b5ebf0d6a431536e9af3ec8942103f757260835b7e439b244a9b10f5645966d7dcff9d2648c400a0d6827f4a64ac421023b3972554e123985b6c3d8575e6fd3384f59a58ef91e0d39ba5905dad49e73722102e32652928f21764e02822d39ffd1075c428e372a06fe7247023d5b60f1d0159621020e002818c48b1d1766f6196e09db90f51e155bbd49be0ad743d1fa6b7e8efcae2103725d482f0c77f4feb1ecbea28f036b30889f462222002e88aa8f8346dce944745eae',
290+
'descriptor':
291+
'wsh(multi(4,02f293c4d026a536a082453f8327f305ae0a0c59350b396205e15fbec2af67390b,03d7b6a7e972f6e1a532f9f49a7cc35055a0ffd7cec5f81728f6a3fdf4dad93672,021f360d51b8eb43422fe942c837ad16e36bab87c5f7567609de9a38e205fb51ed,03a778eaee9cc18a4e5e02a78f403082d4e6f3a9c0d9edaea20b9ad86089de7fc9,02a3c95e41e8272c6842df8c9da492ef5e03bbc4ca17c22ce1f88570e716e187db,032e1d465bc5cdea674337934fb861d097dd7ab20289e4d41de14a6cafcd61d30a,0370fd35da88778a805ce9acc88c0020e3b14cacaa30f99d829207e1896d782ea1,03878a4b831af4fee069964448ccca999071633fcc751d296e8c5325167274febf,0248f8621596029568070dda40bc1e3ace78df320b5ebf0d6a431536e9af3ec894,03f757260835b7e439b244a9b10f5645966d7dcff9d2648c400a0d6827f4a64ac4,023b3972554e123985b6c3d8575e6fd3384f59a58ef91e0d39ba5905dad49e7372,02e32652928f21764e02822d39ffd1075c428e372a06fe7247023d5b60f1d01596,020e002818c48b1d1766f6196e09db90f51e155bbd49be0ad743d1fa6b7e8efcae,03725d482f0c77f4feb1ecbea28f036b30889f462222002e88aa8f8346dce94474))#t7k5jeyy'
292+
}
293+
},
294+
{
295+
'm': 4,
296+
'keys': [
297+
'02f293c4d026a536a082453f8327f305ae0a0c59350b396205e15fbec2af67390b',
298+
'03d7b6a7e972f6e1a532f9f49a7cc35055a0ffd7cec5f81728f6a3fdf4dad93672',
299+
'021f360d51b8eb43422fe942c837ad16e36bab87c5f7567609de9a38e205fb51ed',
300+
'03a778eaee9cc18a4e5e02a78f403082d4e6f3a9c0d9edaea20b9ad86089de7fc9',
301+
'02a3c95e41e8272c6842df8c9da492ef5e03bbc4ca17c22ce1f88570e716e187db',
302+
'032e1d465bc5cdea674337934fb861d097dd7ab20289e4d41de14a6cafcd61d30a',
303+
'0370fd35da88778a805ce9acc88c0020e3b14cacaa30f99d829207e1896d782ea1',
304+
'03878a4b831af4fee069964448ccca999071633fcc751d296e8c5325167274febf',
305+
'0248f8621596029568070dda40bc1e3ace78df320b5ebf0d6a431536e9af3ec894',
306+
'03f757260835b7e439b244a9b10f5645966d7dcff9d2648c400a0d6827f4a64ac4',
307+
'023b3972554e123985b6c3d8575e6fd3384f59a58ef91e0d39ba5905dad49e7372',
308+
'02e32652928f21764e02822d39ffd1075c428e372a06fe7247023d5b60f1d01596',
309+
'020e002818c48b1d1766f6196e09db90f51e155bbd49be0ad743d1fa6b7e8efcae',
310+
'03725d482f0c77f4feb1ecbea28f036b30889f462222002e88aa8f8346dce94474'
311+
],
312+
'address_type': 'legacy',
313+
'result': {
314+
'address': '2NDLRy5WPdnfPYyKYfBCfJXEce3QQhZD8ps',
315+
'redeemScript':
316+
'542102f293c4d026a536a082453f8327f305ae0a0c59350b396205e15fbec2af67390b2103d7b6a7e972f6e1a532f9f49a7cc35055a0ffd7cec5f81728f6a3fdf4dad9367221021f360d51b8eb43422fe942c837ad16e36bab87c5f7567609de9a38e205fb51ed2103a778eaee9cc18a4e5e02a78f403082d4e6f3a9c0d9edaea20b9ad86089de7fc92102a3c95e41e8272c6842df8c9da492ef5e03bbc4ca17c22ce1f88570e716e187db21032e1d465bc5cdea674337934fb861d097dd7ab20289e4d41de14a6cafcd61d30a210370fd35da88778a805ce9acc88c0020e3b14cacaa30f99d829207e1896d782ea12103878a4b831af4fee069964448ccca999071633fcc751d296e8c5325167274febf210248f8621596029568070dda40bc1e3ace78df320b5ebf0d6a431536e9af3ec8942103f757260835b7e439b244a9b10f5645966d7dcff9d2648c400a0d6827f4a64ac421023b3972554e123985b6c3d8575e6fd3384f59a58ef91e0d39ba5905dad49e73722102e32652928f21764e02822d39ffd1075c428e372a06fe7247023d5b60f1d0159621020e002818c48b1d1766f6196e09db90f51e155bbd49be0ad743d1fa6b7e8efcae2103725d482f0c77f4feb1ecbea28f036b30889f462222002e88aa8f8346dce944745eae',
317+
'descriptor':
318+
'sh(multi(4,02f293c4d026a536a082453f8327f305ae0a0c59350b396205e15fbec2af67390b,03d7b6a7e972f6e1a532f9f49a7cc35055a0ffd7cec5f81728f6a3fdf4dad93672,021f360d51b8eb43422fe942c837ad16e36bab87c5f7567609de9a38e205fb51ed,03a778eaee9cc18a4e5e02a78f403082d4e6f3a9c0d9edaea20b9ad86089de7fc9,02a3c95e41e8272c6842df8c9da492ef5e03bbc4ca17c22ce1f88570e716e187db,032e1d465bc5cdea674337934fb861d097dd7ab20289e4d41de14a6cafcd61d30a,0370fd35da88778a805ce9acc88c0020e3b14cacaa30f99d829207e1896d782ea1,03878a4b831af4fee069964448ccca999071633fcc751d296e8c5325167274febf,0248f8621596029568070dda40bc1e3ace78df320b5ebf0d6a431536e9af3ec894,03f757260835b7e439b244a9b10f5645966d7dcff9d2648c400a0d6827f4a64ac4,023b3972554e123985b6c3d8575e6fd3384f59a58ef91e0d39ba5905dad49e7372,02e32652928f21764e02822d39ffd1075c428e372a06fe7247023d5b60f1d01596,020e002818c48b1d1766f6196e09db90f51e155bbd49be0ad743d1fa6b7e8efcae,03725d482f0c77f4feb1ecbea28f036b30889f462222002e88aa8f8346dce94474))#kcuhkkas'
319+
}
320+
},
321+
{
322+
'm': 1,
323+
'keys': [
324+
'02f293c4d026a536a082453f8327f305ae0a0c59350b396205e15fbec2af67390b',
325+
'03d7b6a7e972f6e1a532f9f49a7cc35055a0ffd7cec5f81728f6a3fdf4dad93672'
326+
],
327+
'address_type': 'BECH32',
328+
'error': `Unknown address type 'BECH32'.`
329+
},
330+
{
331+
'm': 4,
332+
'n': 1,
333+
'error': 'Invalid m and n values.'
334+
},
335+
{
336+
'm': 4,
337+
'keys': [
338+
'02f293c4d026a536a082453f8327f305ae0a0c59350b396205e15fbec2af67390b',
339+
'03d7b6a7e972f6e1a532f9f49a7cc35055a0ffd7cec5f81728f6a3fdf4dad93672',
340+
'021f360d51b8eb43422fe942c837ad16e36bab87c5f7567609de9a38e205fb51ed',
341+
'03a778eaee9cc18a4e5e02a78f403082d4e6f3a9c0d9edaea20b9ad86089de7fc9',
342+
'02a3c95e41e8272c6842df8c9da492ef5e03bbc4ca17c22ce1f88570e716e187db',
343+
'032e1d465bc5cdea674337934fb861d097dd7ab20289e4d41de14a6cafcd61d30a',
344+
'0370fd35da88778a805ce9acc88c0020e3b14cacaa30f99d829207e1896d782ea1',
345+
'03878a4b831af4fee069964448ccca999071633fcc751d296e8c5325167274febf',
346+
'0248f8621596029568070dda40bc1e3ace78df320b5ebf0d6a431536e9af3ec894',
347+
'03f757260835b7e439b244a9b10f5645966d7dcff9d2648c400a0d6827f4a64ac4',
348+
'023b3972554e123985b6c3d8575e6fd3384f59a58ef91e0d39ba5905dad49e7372',
349+
'02e32652928f21764e02822d39ffd1075c428e372a06fe7247023d5b60f1d01596',
350+
'020e002818c48b1d1766f6196e09db90f51e155bbd49be0ad743d1fa6b7e8efcae',
351+
'03725d482f0c77f4feb1ecbea28f036b30889f462222002e88aa8f8346dce94474',
352+
'0370fd35da88778a805ce9acc88c0020e3b14cacaa30f99d829207e1896d782ea1',
353+
'03878a4b831af4fee069964448ccca999071633fcc751d296e8c5325167274febf',
354+
'0248f8621596029568070dda40bc1e3ace78df320b5ebf0d6a431536e9af3ec894',
355+
'03f757260835b7e439b244a9b10f5645966d7dcff9d2648c400a0d6827f4a64ac4',
356+
'023b3972554e123985b6c3d8575e6fd3384f59a58ef91e0d39ba5905dad49e7372'
357+
],
358+
'address_type': 'legacy',
359+
'error': 'P2SH script is too large (649 > 520)'
360+
}
361+
];
362+
363+
for (const test of data) {
364+
try {
365+
const result = test.address_type ? await nclient.execute('createmultisig', [test.m, test.keys, test.address_type]) : await nclient.execute('createmultisig', [test.m, test.keys, test.address_type]);
366+
assert.deepStrictEqual(result, test.result);
367+
} catch (e) {
368+
assert.strictEqual(e.message, test.error);
369+
}
370+
}
371+
});
372+
237373
it('should rpc getblockhash', async () => {
238374
const info = await nclient.execute('getblockhash', [node.chain.tip.height]);
239375
assert.strictEqual(util.revHex(node.chain.tip.hash), info);

0 commit comments

Comments
 (0)