UNPKG

4.84 kBJavaScriptView Raw
1'use strict';
2Object.defineProperty(exports, '__esModule', { value: true });
3exports.p2ms = void 0;
4const networks_1 = require('../networks');
5const bscript = require('../script');
6const types_1 = require('../types');
7const lazy = require('./lazy');
8const OPS = bscript.OPS;
9const OP_INT_BASE = OPS.OP_RESERVED; // OP_1 - 1
10function stacksEqual(a, b) {
11 if (a.length !== b.length) return false;
12 return a.every((x, i) => {
13 return x.equals(b[i]);
14 });
15}
16// input: OP_0 [signatures ...]
17// output: m [pubKeys ...] n OP_CHECKMULTISIG
18function p2ms(a, opts) {
19 if (
20 !a.input &&
21 !a.output &&
22 !(a.pubkeys && a.m !== undefined) &&
23 !a.signatures
24 )
25 throw new TypeError('Not enough data');
26 opts = Object.assign({ validate: true }, opts || {});
27 function isAcceptableSignature(x) {
28 return (
29 bscript.isCanonicalScriptSignature(x) ||
30 (opts.allowIncomplete && x === OPS.OP_0) !== undefined
31 );
32 }
33 (0, types_1.typeforce)(
34 {
35 network: types_1.typeforce.maybe(types_1.typeforce.Object),
36 m: types_1.typeforce.maybe(types_1.typeforce.Number),
37 n: types_1.typeforce.maybe(types_1.typeforce.Number),
38 output: types_1.typeforce.maybe(types_1.typeforce.Buffer),
39 pubkeys: types_1.typeforce.maybe(
40 types_1.typeforce.arrayOf(types_1.isPoint),
41 ),
42 signatures: types_1.typeforce.maybe(
43 types_1.typeforce.arrayOf(isAcceptableSignature),
44 ),
45 input: types_1.typeforce.maybe(types_1.typeforce.Buffer),
46 },
47 a,
48 );
49 const network = a.network || networks_1.bitcoin;
50 const o = { network };
51 let chunks = [];
52 let decoded = false;
53 function decode(output) {
54 if (decoded) return;
55 decoded = true;
56 chunks = bscript.decompile(output);
57 o.m = chunks[0] - OP_INT_BASE;
58 o.n = chunks[chunks.length - 2] - OP_INT_BASE;
59 o.pubkeys = chunks.slice(1, -2);
60 }
61 lazy.prop(o, 'output', () => {
62 if (!a.m) return;
63 if (!o.n) return;
64 if (!a.pubkeys) return;
65 return bscript.compile(
66 [].concat(
67 OP_INT_BASE + a.m,
68 a.pubkeys,
69 OP_INT_BASE + o.n,
70 OPS.OP_CHECKMULTISIG,
71 ),
72 );
73 });
74 lazy.prop(o, 'm', () => {
75 if (!o.output) return;
76 decode(o.output);
77 return o.m;
78 });
79 lazy.prop(o, 'n', () => {
80 if (!o.pubkeys) return;
81 return o.pubkeys.length;
82 });
83 lazy.prop(o, 'pubkeys', () => {
84 if (!a.output) return;
85 decode(a.output);
86 return o.pubkeys;
87 });
88 lazy.prop(o, 'signatures', () => {
89 if (!a.input) return;
90 return bscript.decompile(a.input).slice(1);
91 });
92 lazy.prop(o, 'input', () => {
93 if (!a.signatures) return;
94 return bscript.compile([OPS.OP_0].concat(a.signatures));
95 });
96 lazy.prop(o, 'witness', () => {
97 if (!o.input) return;
98 return [];
99 });
100 lazy.prop(o, 'name', () => {
101 if (!o.m || !o.n) return;
102 return `p2ms(${o.m} of ${o.n})`;
103 });
104 // extended validation
105 if (opts.validate) {
106 if (a.output) {
107 decode(a.output);
108 if (!types_1.typeforce.Number(chunks[0]))
109 throw new TypeError('Output is invalid');
110 if (!types_1.typeforce.Number(chunks[chunks.length - 2]))
111 throw new TypeError('Output is invalid');
112 if (chunks[chunks.length - 1] !== OPS.OP_CHECKMULTISIG)
113 throw new TypeError('Output is invalid');
114 if (o.m <= 0 || o.n > 16 || o.m > o.n || o.n !== chunks.length - 3)
115 throw new TypeError('Output is invalid');
116 if (!o.pubkeys.every(x => (0, types_1.isPoint)(x)))
117 throw new TypeError('Output is invalid');
118 if (a.m !== undefined && a.m !== o.m) throw new TypeError('m mismatch');
119 if (a.n !== undefined && a.n !== o.n) throw new TypeError('n mismatch');
120 if (a.pubkeys && !stacksEqual(a.pubkeys, o.pubkeys))
121 throw new TypeError('Pubkeys mismatch');
122 }
123 if (a.pubkeys) {
124 if (a.n !== undefined && a.n !== a.pubkeys.length)
125 throw new TypeError('Pubkey count mismatch');
126 o.n = a.pubkeys.length;
127 if (o.n < o.m) throw new TypeError('Pubkey count cannot be less than m');
128 }
129 if (a.signatures) {
130 if (a.signatures.length < o.m)
131 throw new TypeError('Not enough signatures provided');
132 if (a.signatures.length > o.m)
133 throw new TypeError('Too many signatures provided');
134 }
135 if (a.input) {
136 if (a.input[0] !== OPS.OP_0) throw new TypeError('Input is invalid');
137 if (
138 o.signatures.length === 0 ||
139 !o.signatures.every(isAcceptableSignature)
140 )
141 throw new TypeError('Input has invalid signature(s)');
142 if (a.signatures && !stacksEqual(a.signatures, o.signatures))
143 throw new TypeError('Signature mismatch');
144 if (a.m !== undefined && a.m !== a.signatures.length)
145 throw new TypeError('Signature count mismatch');
146 }
147 }
148 return Object.assign(o, a);
149}
150exports.p2ms = p2ms;