Skip to content

Commit

Permalink
feat<node>: add descriptor support in createmultisig rpc
Browse files Browse the repository at this point in the history
  • Loading branch information
Vasu-08 committed Aug 17, 2023
1 parent 2e4f450 commit 3599c13
Show file tree
Hide file tree
Showing 3 changed files with 209 additions and 15 deletions.
4 changes: 2 additions & 2 deletions lib/descriptor/abstractdescriptor.js
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ class AbstractDescriptor {
* @returns {Script[]}
*/

generateScripts(pos) {
generateScripts(pos = 0) {
const pubkeys = [];
const subscripts = [];

Expand Down Expand Up @@ -274,7 +274,7 @@ class AbstractDescriptor {
* @returns {Address[]}
*/

getAddresses(pos) {
getAddresses(pos = 0) {
const scripts = this.generateScripts(pos);
const addresses = [];

Expand Down
60 changes: 47 additions & 13 deletions lib/node/rpc.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,15 @@ const TX = require('../primitives/tx');
const consensus = require('../protocol/consensus');
const pkg = require('../pkg');
const {filters} = require('../blockstore/common');
const {createChecksum} = require('../descriptor/common');
const MultisigDescriptor = require('../descriptor/type/multisig');
const SHDescriptor = require('../descriptor/type/sh');
const WSHDescriptor = require('../descriptor/type/wsh');
const {parse} = require('../descriptor/parser');
const RPCBase = bweb.RPC;
const RPCError = bweb.RPCError;
const {
createChecksum, outputTypes, scriptContext
} = require('../descriptor/common');

/*
* Constants
Expand Down Expand Up @@ -2050,17 +2055,28 @@ class RPC extends RPCBase {
*/

async createMultisig(args, help) {
if (help || args.length < 2 || args.length > 2) {
if (help || args.length < 2 || args.length > 3) {
throw new RPCError(errs.MISC_ERROR,
'createmultisig nrequired ["key",...]');
'createmultisig nrequired ["key",...] (address_type)');
}

const valid = new Validator(args);
const keys = valid.array(1, []);
let outputType = valid.str(2);

if (outputType === null) {
outputType = outputTypes.LEGACY;
}

assert(
Object.values(outputTypes).includes(outputType),
`Unknown address type '${outputType}'.`
);

const m = valid.u32(0, 0);
const n = keys.length;

if (m < 1 || n < m || n > 16)
if (m < 1 || n < m || n > 20)
throw new RPCError(errs.INVALID_PARAMETER, 'Invalid m and n values.');

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

keys[i] = key;
keys[i] = items.str(i, '');
}

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

if (script.getSize() > consensus.MAX_SCRIPT_PUSH) {
throw new RPCError(errs.VERIFY_ERROR,
'Redeem script exceeds size limit.');
}
const subdesc = MultisigDescriptor.fromString(
`multi(${m},${keys.join(',')})`, this.network, context
);

const addr = script.getAddress();
let descriptor;

const options = {
subdescriptors: [subdesc], network: this.network
};

switch (outputType) {
case outputTypes.LEGACY:
descriptor = SHDescriptor.fromOptions(options);
break;
case outputTypes.BECH32:
descriptor = WSHDescriptor.fromOptions(options);
break;
case outputTypes.P2SH_SEGWIT: {
options.subdescriptors = [WSHDescriptor.fromOptions(options)];
descriptor = SHDescriptor.fromOptions(options);
}
}

return {
address: addr.toString(this.network),
redeemScript: script.toJSON()
address: descriptor.getAddresses()[0],
redeemScript: subdesc.generateScripts()[0].toJSON(),
descriptor: descriptor.toString()
};
}

Expand Down
Loading

0 comments on commit 3599c13

Please sign in to comment.