UNPKG

35.7 kBJavaScriptView Raw
1'use strict';
2
3var Address = require('../address');
4var BufferReader = require('../encoding/bufferreader');
5var BufferWriter = require('../encoding/bufferwriter');
6var Hash = require('../crypto/hash');
7var Opcode = require('../opcode');
8var PublicKey = require('../publickey');
9var Signature = require('../crypto/signature');
10var Networks = require('../networks');
11var $ = require('../util/preconditions');
12var _ = require('lodash');
13var errors = require('../errors');
14var buffer = require('buffer');
15var BufferUtil = require('../util/buffer');
16var JSUtil = require('../util/js');
17
18/**
19 * A bitcoin transaction script. Each transaction's inputs and outputs
20 * has a script that is evaluated to validate it's spending.
21 *
22 * See https://en.bitcoin.it/wiki/Script
23 *
24 * @constructor
25 * @param {Object|string|Buffer=} from optional data to populate script
26 */
27var Script = function Script(from) {
28 if (!(this instanceof Script)) {
29 return new Script(from);
30 }
31 this.chunks = [];
32
33 if (BufferUtil.isBuffer(from)) {
34 return Script.fromBuffer(from);
35 } else if (from instanceof Address) {
36 return Script.fromAddress(from);
37 } else if (from instanceof Script) {
38 return Script.fromBuffer(from.toBuffer());
39 } else if (_.isString(from)) {
40 return Script.fromString(from);
41 } else if (_.isObject(from) && _.isArray(from.chunks)) {
42 this.set(from);
43 }
44};
45
46Script.VERIFY_TAPROOT = (1 << 17);
47
48
49Script.prototype.set = function(obj) {
50 $.checkArgument(_.isObject(obj));
51 $.checkArgument(_.isArray(obj.chunks));
52 this.chunks = obj.chunks;
53 return this;
54};
55
56Script.fromBuffer = function(buffer) {
57 var script = new Script();
58 script.chunks = [];
59
60 var br = new BufferReader(buffer);
61 while (!br.finished()) {
62 try {
63 var opcodenum = br.readUInt8();
64
65 var len, buf;
66 if (opcodenum > 0 && opcodenum < Opcode.OP_PUSHDATA1) {
67 len = opcodenum;
68 script.chunks.push({
69 buf: br.read(len),
70 len: len,
71 opcodenum: opcodenum
72 });
73 } else if (opcodenum === Opcode.OP_PUSHDATA1) {
74 len = br.readUInt8();
75 buf = br.read(len);
76 script.chunks.push({
77 buf: buf,
78 len: len,
79 opcodenum: opcodenum
80 });
81 } else if (opcodenum === Opcode.OP_PUSHDATA2) {
82 len = br.readUInt16LE();
83 buf = br.read(len);
84 script.chunks.push({
85 buf: buf,
86 len: len,
87 opcodenum: opcodenum
88 });
89 } else if (opcodenum === Opcode.OP_PUSHDATA4) {
90 len = br.readUInt32LE();
91 buf = br.read(len);
92 script.chunks.push({
93 buf: buf,
94 len: len,
95 opcodenum: opcodenum
96 });
97 } else {
98 script.chunks.push({
99 opcodenum: opcodenum
100 });
101 }
102 } catch (e) {
103 if (e instanceof RangeError) {
104 throw new errors.Script.InvalidBuffer(buffer.toString('hex'));
105 }
106 throw e;
107 }
108 }
109
110 return script;
111};
112
113Script.prototype.toBuffer = function() {
114 var bw = new BufferWriter();
115
116 for (var i = 0; i < this.chunks.length; i++) {
117 var chunk = this.chunks[i];
118 var opcodenum = chunk.opcodenum;
119 bw.writeUInt8(chunk.opcodenum);
120 if (chunk.buf) {
121 if (opcodenum < Opcode.OP_PUSHDATA1) {
122 bw.write(chunk.buf);
123 } else if (opcodenum === Opcode.OP_PUSHDATA1) {
124 bw.writeUInt8(chunk.len);
125 bw.write(chunk.buf);
126 } else if (opcodenum === Opcode.OP_PUSHDATA2) {
127 bw.writeUInt16LE(chunk.len);
128 bw.write(chunk.buf);
129 } else if (opcodenum === Opcode.OP_PUSHDATA4) {
130 bw.writeUInt32LE(chunk.len);
131 bw.write(chunk.buf);
132 }
133 }
134 }
135
136 return bw.concat();
137};
138
139Script.fromASM = function(str) {
140 var script = new Script();
141 script.chunks = [];
142
143 var tokens = str.split(' ');
144 var i = 0;
145 while (i < tokens.length) {
146 var token = tokens[i];
147 var opcode = Opcode(token);
148 var opcodenum = opcode.toNumber();
149
150 if (_.isUndefined(opcodenum)) {
151 var buf = Buffer.from(tokens[i], 'hex');
152 script.chunks.push({
153 buf: buf,
154 len: buf.length,
155 opcodenum: buf.length
156 });
157 i = i + 1;
158 } else if (opcodenum === Opcode.OP_PUSHDATA1 ||
159 opcodenum === Opcode.OP_PUSHDATA2 ||
160 opcodenum === Opcode.OP_PUSHDATA4) {
161 script.chunks.push({
162 buf: Buffer.from(tokens[i + 2], 'hex'),
163 len: parseInt(tokens[i + 1]),
164 opcodenum: opcodenum
165 });
166 i = i + 3;
167 } else {
168 script.chunks.push({
169 opcodenum: opcodenum
170 });
171 i = i + 1;
172 }
173 }
174 return script;
175};
176
177Script.fromHex = function(str) {
178 return new Script(Buffer.from(str, 'hex'));
179};
180
181Script.fromString = function(str) {
182 if (JSUtil.isHexa(str) || str.length === 0) {
183 return new Script(Buffer.from(str, 'hex'));
184 }
185 var script = new Script();
186 script.chunks = [];
187
188 var tokens = str.split(' ');
189 var i = 0;
190 while (i < tokens.length) {
191 var token = tokens[i];
192 var opcode = Opcode(token);
193 var opcodenum = opcode.toNumber();
194
195 if (_.isUndefined(opcodenum)) {
196 opcodenum = parseInt(token);
197 if (opcodenum > 0 && opcodenum < Opcode.OP_PUSHDATA1) {
198 script.chunks.push({
199 buf: Buffer.from(tokens[i + 1].slice(2), 'hex'),
200 len: opcodenum,
201 opcodenum: opcodenum
202 });
203 i = i + 2;
204 } else {
205 throw new Error('Invalid script: ' + JSON.stringify(str));
206 }
207 } else if (opcodenum === Opcode.OP_PUSHDATA1 ||
208 opcodenum === Opcode.OP_PUSHDATA2 ||
209 opcodenum === Opcode.OP_PUSHDATA4) {
210 if (tokens[i + 2].slice(0, 2) !== '0x') {
211 throw new Error('Pushdata data must start with 0x');
212 }
213 script.chunks.push({
214 buf: Buffer.from(tokens[i + 2].slice(2), 'hex'),
215 len: parseInt(tokens[i + 1]),
216 opcodenum: opcodenum
217 });
218 i = i + 3;
219 } else {
220 script.chunks.push({
221 opcodenum: opcodenum
222 });
223 i = i + 1;
224 }
225 }
226 return script;
227};
228
229Script.prototype._chunkToString = function(chunk, type) {
230 var opcodenum = chunk.opcodenum;
231 var asm = (type === 'asm');
232 var str = '';
233 if (!chunk.buf) {
234 // no data chunk
235 if (typeof Opcode.reverseMap[opcodenum] !== 'undefined') {
236 if (asm) {
237 // A few cases where the opcode name differs from reverseMap
238 // aside from 1 to 16 data pushes.
239 if (opcodenum === 0) {
240 // OP_0 -> 0
241 str = str + ' 0';
242 } else if(opcodenum === 79) {
243 // OP_1NEGATE -> 1
244 str = str + ' -1';
245 } else {
246 str = str + ' ' + Opcode(opcodenum).toString();
247 }
248 } else {
249 str = str + ' ' + Opcode(opcodenum).toString();
250 }
251 } else {
252 var numstr = opcodenum.toString(16);
253 if (numstr.length % 2 !== 0) {
254 numstr = '0' + numstr;
255 }
256 if (asm) {
257 str = str + ' ' + numstr;
258 } else {
259 str = str + ' ' + '0x' + numstr;
260 }
261 }
262 } else {
263 // data chunk
264 if (!asm && opcodenum === Opcode.OP_PUSHDATA1 ||
265 opcodenum === Opcode.OP_PUSHDATA2 ||
266 opcodenum === Opcode.OP_PUSHDATA4) {
267 str = str + ' ' + Opcode(opcodenum).toString();
268 }
269 if (chunk.len > 0) {
270 if (asm) {
271 str = str + ' ' + chunk.buf.toString('hex');
272 } else {
273 str = str + ' ' + chunk.len + ' ' + '0x' + chunk.buf.toString('hex');
274 }
275 }
276 }
277 return str;
278};
279
280Script.prototype.toASM = function() {
281 var str = '';
282 for (var i = 0; i < this.chunks.length; i++) {
283 var chunk = this.chunks[i];
284 str += this._chunkToString(chunk, 'asm');
285 }
286
287 return str.substr(1);
288};
289
290Script.prototype.toString = function() {
291 var str = '';
292 for (var i = 0; i < this.chunks.length; i++) {
293 var chunk = this.chunks[i];
294 str += this._chunkToString(chunk);
295 }
296
297 return str.substr(1);
298};
299
300Script.prototype.toHex = function() {
301 return this.toBuffer().toString('hex');
302};
303
304Script.prototype.inspect = function() {
305 return '<Script: ' + this.toString() + '>';
306};
307
308// script classification methods
309
310/**
311 * @returns {boolean} if this is a pay to pubkey hash output script
312 */
313Script.prototype.isPublicKeyHashOut = function() {
314 return !!(this.chunks.length === 5 &&
315 this.chunks[0].opcodenum === Opcode.OP_DUP &&
316 this.chunks[1].opcodenum === Opcode.OP_HASH160 &&
317 this.chunks[2].buf &&
318 this.chunks[2].buf.length === 20 &&
319 this.chunks[3].opcodenum === Opcode.OP_EQUALVERIFY &&
320 this.chunks[4].opcodenum === Opcode.OP_CHECKSIG);
321};
322
323/**
324 * @returns {boolean} if this is a pay to public key hash input script
325 */
326Script.prototype.isPublicKeyHashIn = function() {
327 if (this.chunks.length === 2) {
328 var signatureBuf = this.chunks[0].buf;
329 var pubkeyBuf = this.chunks[1].buf;
330 if (signatureBuf &&
331 signatureBuf.length &&
332 signatureBuf[0] === 0x30 &&
333 pubkeyBuf &&
334 pubkeyBuf.length
335 ) {
336 var version = pubkeyBuf[0];
337 if ((version === 0x04 ||
338 version === 0x06 ||
339 version === 0x07) && pubkeyBuf.length === 65) {
340 return true;
341 } else if ((version === 0x03 || version === 0x02) && pubkeyBuf.length === 33) {
342 return true;
343 }
344 }
345 }
346 return false;
347};
348
349Script.prototype.getPublicKey = function() {
350 $.checkState(this.isPublicKeyOut(), 'Can\'t retrieve PublicKey from a non-PK output');
351 return this.chunks[0].buf;
352};
353
354Script.prototype.getPublicKeyHash = function() {
355 if (this.isPublicKeyHashOut()) {
356 return this.chunks[2].buf;
357 } else if (this.isWitnessPublicKeyHashOut()) {
358 return this.chunks[1].buf;
359 } else {
360 throw new Error('Can\'t retrieve PublicKeyHash from a non-PKH output');
361 }
362};
363
364/**
365 * @returns {boolean} if this is a public key output script
366 */
367Script.prototype.isPublicKeyOut = function() {
368 if (this.chunks.length === 2 &&
369 this.chunks[0].buf &&
370 this.chunks[0].buf.length &&
371 this.chunks[1].opcodenum === Opcode.OP_CHECKSIG) {
372 var pubkeyBuf = this.chunks[0].buf;
373 var version = pubkeyBuf[0];
374 var isVersion = false;
375 if ((version === 0x04 ||
376 version === 0x06 ||
377 version === 0x07) && pubkeyBuf.length === 65) {
378 isVersion = true;
379 } else if ((version === 0x03 || version === 0x02) && pubkeyBuf.length === 33) {
380 isVersion = true;
381 }
382 if (isVersion) {
383 return PublicKey.isValid(pubkeyBuf);
384 }
385 }
386 return false;
387};
388
389/**
390 * @returns {boolean} if this is a pay to public key input script
391 */
392Script.prototype.isPublicKeyIn = function() {
393 if (this.chunks.length === 1) {
394 var signatureBuf = this.chunks[0].buf;
395 if (signatureBuf &&
396 signatureBuf.length &&
397 signatureBuf[0] === 0x30) {
398 return true;
399 }
400 }
401 return false;
402};
403
404/**
405 * @returns {boolean} if this is a p2sh output script
406 */
407Script.prototype.isScriptHashOut = function() {
408 var buf = this.toBuffer();
409 return (buf.length === 23 &&
410 buf[0] === Opcode.OP_HASH160 &&
411 buf[1] === 0x14 &&
412 buf[buf.length - 1] === Opcode.OP_EQUAL);
413};
414
415/**
416 * @returns {boolean} if this is a p2wsh output script
417 */
418Script.prototype.isWitnessScriptHashOut = function() {
419 var buf = this.toBuffer();
420 return (buf.length === 34 && buf[0] === Opcode.OP_0 && buf[1] === 32);
421};
422
423/**
424 * @returns {boolean} if this is a p2wpkh output script
425 */
426Script.prototype.isWitnessPublicKeyHashOut = function() {
427 var buf = this.toBuffer();
428 return (buf.length === 22 && buf[0] === Opcode.OP_0 && buf[1] === 20);
429};
430
431/**
432 * @returns {boolean} if this is a p2tr output script
433 */
434Script.prototype.isTaproot = function() {
435 var buf = this.toBuffer();
436 return (buf.length === 34 && buf[0] === Opcode.OP_1 && buf[1] === 32);
437}
438
439/**
440 * @param {Object=} values - The return values
441 * @param {Number} values.version - Set with the witness version
442 * @param {Buffer} values.program - Set with the witness program
443 * @returns {boolean} if this is a p2wpkh output script
444 */
445Script.prototype.isWitnessProgram = function(values) {
446 if (!values) {
447 values = {};
448 }
449 var buf = this.toBuffer();
450 if (buf.length < 4 || buf.length > 42) {
451 return false;
452 }
453 if (buf[0] !== Opcode.OP_0 && !(buf[0] >= Opcode.OP_1 && buf[0] <= Opcode.OP_16)) {
454 return false;
455 }
456
457 if (buf.length === buf[1] + 2) {
458 values.version = buf[0];
459 values.program = buf.slice(2, buf.length);
460 return true;
461 }
462
463 return false;
464};
465
466/**
467 * @returns {boolean} if this is a p2sh input script
468 * Note that these are frequently indistinguishable from pubkeyhashin
469 */
470Script.prototype.isScriptHashIn = function() {
471 if (this.chunks.length <= 1) {
472 return false;
473 }
474 var redeemChunk = this.chunks[this.chunks.length - 1];
475 var redeemBuf = redeemChunk.buf;
476 if (!redeemBuf) {
477 return false;
478 }
479
480 var redeemScript;
481 try {
482 redeemScript = Script.fromBuffer(redeemBuf);
483 } catch (e) {
484 if (e instanceof errors.Script.InvalidBuffer) {
485 return false;
486 }
487 throw e;
488 }
489 var type = redeemScript.classify();
490 return type !== Script.types.UNKNOWN;
491};
492
493/**
494 * @returns {boolean} if this is a mutlsig output script
495 */
496Script.prototype.isMultisigOut = function() {
497 return (this.chunks.length > 3 &&
498 Opcode.isSmallIntOp(this.chunks[0].opcodenum) &&
499 this.chunks.slice(1, this.chunks.length - 2).every(function(obj) {
500 return obj.buf && BufferUtil.isBuffer(obj.buf);
501 }) &&
502 Opcode.isSmallIntOp(this.chunks[this.chunks.length - 2].opcodenum) &&
503 this.chunks[this.chunks.length - 1].opcodenum === Opcode.OP_CHECKMULTISIG);
504};
505
506
507/**
508 * @returns {boolean} if this is a multisig input script
509 */
510Script.prototype.isMultisigIn = function() {
511 return this.chunks.length >= 2 &&
512 this.chunks[0].opcodenum === 0 &&
513 this.chunks.slice(1, this.chunks.length).every(function(obj) {
514 return obj.buf &&
515 BufferUtil.isBuffer(obj.buf) &&
516 Signature.isTxDER(obj.buf);
517 });
518};
519
520/**
521 * @returns {boolean} true if this is a valid standard OP_RETURN output
522 */
523Script.prototype.isDataOut = function() {
524 return this.chunks.length >= 1 &&
525 this.chunks[0].opcodenum === Opcode.OP_RETURN &&
526 (this.chunks.length === 1 ||
527 (this.chunks.length === 2 &&
528 this.chunks[1].buf &&
529 this.chunks[1].buf.length <= Script.OP_RETURN_STANDARD_SIZE &&
530 this.chunks[1].length === this.chunks.len));
531};
532
533/**
534 * Retrieve the associated data for this script.
535 * In the case of a pay to public key hash, P2SH, P2WSH, or P2WPKH, return the hash.
536 * In the case of a standard OP_RETURN, return the data
537 * @returns {Buffer}
538 */
539Script.prototype.getData = function() {
540 if (this.isDataOut() || this.isScriptHashOut() || this.isWitnessScriptHashOut() || this.isWitnessPublicKeyHashOut() || this.isTaproot()) {
541 if (_.isUndefined(this.chunks[1])) {
542 return Buffer.alloc(0);
543 } else {
544 return Buffer.from(this.chunks[1].buf);
545 }
546 }
547 if (this.isPublicKeyHashOut()) {
548 return Buffer.from(this.chunks[2].buf);
549 }
550 throw new Error('Unrecognized script type to get data from');
551};
552
553/**
554 * @returns {boolean} if the script is only composed of data pushing
555 * opcodes or small int opcodes (OP_0, OP_1, ..., OP_16)
556 */
557Script.prototype.isPushOnly = function() {
558 return _.every(this.chunks, function(chunk) {
559 return chunk.opcodenum <= Opcode.OP_16;
560 });
561};
562
563
564Script.types = {};
565Script.types.UNKNOWN = 'Unknown';
566Script.types.PUBKEY_OUT = 'Pay to public key';
567Script.types.PUBKEY_IN = 'Spend from public key';
568Script.types.PUBKEYHASH_OUT = 'Pay to public key hash';
569Script.types.PUBKEYHASH_IN = 'Spend from public key hash';
570Script.types.SCRIPTHASH_OUT = 'Pay to script hash';
571Script.types.SCRIPTHASH_IN = 'Spend from script hash';
572Script.types.MULTISIG_OUT = 'Pay to multisig';
573Script.types.MULTISIG_IN = 'Spend from multisig';
574Script.types.DATA_OUT = 'Data push';
575
576Script.OP_RETURN_STANDARD_SIZE = 80;
577
578/**
579 * @returns {object} The Script type if it is a known form,
580 * or Script.UNKNOWN if it isn't
581 */
582Script.prototype.classify = function() {
583 if (this._isInput) {
584 return this.classifyInput();
585 } else if (this._isOutput) {
586 return this.classifyOutput();
587 } else {
588 var outputType = this.classifyOutput();
589 return outputType != Script.types.UNKNOWN ? outputType : this.classifyInput();
590 }
591};
592
593Script.outputIdentifiers = {};
594Script.outputIdentifiers.PUBKEY_OUT = Script.prototype.isPublicKeyOut;
595Script.outputIdentifiers.PUBKEYHASH_OUT = Script.prototype.isPublicKeyHashOut;
596Script.outputIdentifiers.MULTISIG_OUT = Script.prototype.isMultisigOut;
597Script.outputIdentifiers.SCRIPTHASH_OUT = Script.prototype.isScriptHashOut;
598Script.outputIdentifiers.DATA_OUT = Script.prototype.isDataOut;
599
600/**
601 * @returns {object} The Script type if it is a known form,
602 * or Script.UNKNOWN if it isn't
603 */
604Script.prototype.classifyOutput = function() {
605 for (var type in Script.outputIdentifiers) {
606 if (Script.outputIdentifiers[type].bind(this)()) {
607 return Script.types[type];
608 }
609 }
610 return Script.types.UNKNOWN;
611};
612
613Script.inputIdentifiers = {};
614Script.inputIdentifiers.PUBKEY_IN = Script.prototype.isPublicKeyIn;
615Script.inputIdentifiers.PUBKEYHASH_IN = Script.prototype.isPublicKeyHashIn;
616Script.inputIdentifiers.MULTISIG_IN = Script.prototype.isMultisigIn;
617Script.inputIdentifiers.SCRIPTHASH_IN = Script.prototype.isScriptHashIn;
618
619/**
620 * @returns {object} The Script type if it is a known form,
621 * or Script.UNKNOWN if it isn't
622 */
623Script.prototype.classifyInput = function() {
624 for (var type in Script.inputIdentifiers) {
625 if (Script.inputIdentifiers[type].bind(this)()) {
626 return Script.types[type];
627 }
628 }
629 return Script.types.UNKNOWN;
630};
631
632
633/**
634 * @returns {boolean} if script is one of the known types
635 */
636Script.prototype.isStandard = function() {
637 // TODO: Add BIP62 compliance
638 return this.classify() !== Script.types.UNKNOWN;
639};
640
641
642// Script construction methods
643
644/**
645 * Adds a script element at the start of the script.
646 * @param {*} obj a string, number, Opcode, Buffer, or object to add
647 * @returns {Script} this script instance
648 */
649Script.prototype.prepend = function(obj) {
650 this._addByType(obj, true);
651 return this;
652};
653
654/**
655 * Compares a script with another script
656 */
657Script.prototype.equals = function(script) {
658 $.checkState(script instanceof Script, 'Must provide another script');
659 if (this.chunks.length !== script.chunks.length) {
660 return false;
661 }
662 var i;
663 for (i = 0; i < this.chunks.length; i++) {
664 if (BufferUtil.isBuffer(this.chunks[i].buf) && !BufferUtil.isBuffer(script.chunks[i].buf)) {
665 return false;
666 }
667 if (BufferUtil.isBuffer(this.chunks[i].buf) && !BufferUtil.equals(this.chunks[i].buf, script.chunks[i].buf)) {
668 return false;
669 } else if (this.chunks[i].opcodenum !== script.chunks[i].opcodenum) {
670 return false;
671 }
672 }
673 return true;
674};
675
676/**
677 * Adds a script element to the end of the script.
678 *
679 * @param {*} obj a string, number, Opcode, Buffer, or object to add
680 * @returns {Script} this script instance
681 *
682 */
683Script.prototype.add = function(obj) {
684 this._addByType(obj, false);
685 return this;
686};
687
688Script.prototype._addByType = function(obj, prepend) {
689 if (typeof obj === 'string') {
690 this._addOpcode(obj, prepend);
691 } else if (typeof obj === 'number') {
692 this._addOpcode(obj, prepend);
693 } else if (obj instanceof Opcode) {
694 this._addOpcode(obj, prepend);
695 } else if (BufferUtil.isBuffer(obj)) {
696 this._addBuffer(obj, prepend);
697 } else if (obj instanceof Script) {
698 this.chunks = this.chunks.concat(obj.chunks);
699 } else if (typeof obj === 'object') {
700 this._insertAtPosition(obj, prepend);
701 } else {
702 throw new Error('Invalid script chunk');
703 }
704};
705
706Script.prototype._insertAtPosition = function(op, prepend) {
707 if (prepend) {
708 this.chunks.unshift(op);
709 } else {
710 this.chunks.push(op);
711 }
712};
713
714Script.prototype._addOpcode = function(opcode, prepend) {
715 var op;
716 if (typeof opcode === 'number') {
717 op = opcode;
718 } else if (opcode instanceof Opcode) {
719 op = opcode.toNumber();
720 } else {
721 op = Opcode(opcode).toNumber();
722 }
723 this._insertAtPosition({
724 opcodenum: op
725 }, prepend);
726 return this;
727};
728
729Script.prototype._addBuffer = function(buf, prepend) {
730 var opcodenum;
731 var len = buf.length;
732 if (len >= 0 && len < Opcode.OP_PUSHDATA1) {
733 opcodenum = len;
734 } else if (len < Math.pow(2, 8)) {
735 opcodenum = Opcode.OP_PUSHDATA1;
736 } else if (len < Math.pow(2, 16)) {
737 opcodenum = Opcode.OP_PUSHDATA2;
738 } else if (len < Math.pow(2, 32)) {
739 opcodenum = Opcode.OP_PUSHDATA4;
740 } else {
741 throw new Error('You can\'t push that much data');
742 }
743 this._insertAtPosition({
744 buf: buf,
745 len: len,
746 opcodenum: opcodenum
747 }, prepend);
748 return this;
749};
750
751Script.prototype.hasCodeseparators = function() {
752 for (var i = 0; i < this.chunks.length; i++) {
753 if (this.chunks[i].opcodenum === Opcode.OP_CODESEPARATOR) {
754 return true;
755 }
756 }
757 return false;
758};
759
760Script.prototype.removeCodeseparators = function() {
761 var chunks = [];
762 for (var i = 0; i < this.chunks.length; i++) {
763 if (this.chunks[i].opcodenum !== Opcode.OP_CODESEPARATOR) {
764 chunks.push(this.chunks[i]);
765 }
766 }
767 this.chunks = chunks;
768 return this;
769};
770
771// high level script builder methods
772
773/**
774 * @returns {Script} a new Multisig output script for given public keys,
775 * requiring m of those public keys to spend
776 * @param {PublicKey[]} publicKeys - list of all public keys controlling the output
777 * @param {number} threshold - amount of required signatures to spend the output
778 * @param {Object=} opts - Several options:
779 * - noSorting: defaults to false, if true, don't sort the given
780 * public keys before creating the script
781 */
782Script.buildMultisigOut = function(publicKeys, threshold, opts) {
783 $.checkArgument(threshold <= publicKeys.length,
784 'Number of required signatures must be less than or equal to the number of public keys');
785 opts = opts || {};
786 var script = new Script();
787 script.add(Opcode.smallInt(threshold));
788 publicKeys = _.map(publicKeys, PublicKey);
789 var sorted = publicKeys;
790 if (!opts.noSorting) {
791 sorted = _.sortBy(publicKeys, function(publicKey) {
792 return publicKey.toString('hex');
793 });
794 }
795 for (var i = 0; i < sorted.length; i++) {
796 var publicKey = sorted[i];
797 script.add(publicKey.toBuffer());
798 }
799 script.add(Opcode.smallInt(publicKeys.length));
800 script.add(Opcode.OP_CHECKMULTISIG);
801 return script;
802};
803
804Script.buildWitnessMultisigOutFromScript = function(script) {
805 if (script instanceof Script) {
806 var s = new Script();
807 s.add(Opcode.OP_0);
808 s.add(Hash.sha256(script.toBuffer()));
809 return s;
810 } else {
811 throw new TypeError('First argument is expected to be a p2sh script');
812 }
813};
814
815/**
816 * A new Multisig input script for the given public keys, requiring m of those public keys to spend
817 *
818 * @param {PublicKey[]} pubkeys list of all public keys controlling the output
819 * @param {number} threshold amount of required signatures to spend the output
820 * @param {Array} signatures and array of signature buffers to append to the script
821 * @param {Object=} opts
822 * @param {boolean=} opts.noSorting don't sort the given public keys before creating the script (false by default)
823 * @param {Script=} opts.cachedMultisig don't recalculate the redeemScript
824 *
825 * @returns {Script}
826 */
827Script.buildMultisigIn = function(pubkeys, threshold, signatures, opts) {
828 $.checkArgument(_.isArray(pubkeys));
829 $.checkArgument(_.isNumber(threshold));
830 $.checkArgument(_.isArray(signatures));
831 opts = opts || {};
832 var s = new Script();
833 s.add(Opcode.OP_0);
834 _.each(signatures, function(signature) {
835 $.checkArgument(BufferUtil.isBuffer(signature), 'Signatures must be an array of Buffers');
836 // TODO: allow signatures to be an array of Signature objects
837 s.add(signature);
838 });
839 return s;
840};
841
842/**
843 * A new P2SH Multisig input script for the given public keys, requiring m of those public keys to spend
844 *
845 * @param {PublicKey[]} pubkeys list of all public keys controlling the output
846 * @param {number} threshold amount of required signatures to spend the output
847 * @param {Array} signatures and array of signature buffers to append to the script
848 * @param {Object=} opts
849 * @param {boolean=} opts.noSorting don't sort the given public keys before creating the script (false by default)
850 * @param {Script=} opts.cachedMultisig don't recalculate the redeemScript
851 *
852 * @returns {Script}
853 */
854Script.buildP2SHMultisigIn = function(pubkeys, threshold, signatures, opts) {
855 $.checkArgument(_.isArray(pubkeys));
856 $.checkArgument(_.isNumber(threshold));
857 $.checkArgument(_.isArray(signatures));
858 opts = opts || {};
859 var s = new Script();
860 s.add(Opcode.OP_0);
861 _.each(signatures, function(signature) {
862 $.checkArgument(BufferUtil.isBuffer(signature), 'Signatures must be an array of Buffers');
863 // TODO: allow signatures to be an array of Signature objects
864 s.add(signature);
865 });
866 s.add((opts.cachedMultisig || Script.buildMultisigOut(pubkeys, threshold, opts)).toBuffer());
867 return s;
868};
869
870/**
871 * @returns {Script} a new pay to public key hash output for the given
872 * address or public key
873 * @param {(Address|PublicKey)} to - destination address or public key
874 */
875Script.buildPublicKeyHashOut = function(to) {
876 $.checkArgument(!_.isUndefined(to));
877 $.checkArgument(to instanceof PublicKey || to instanceof Address || _.isString(to));
878 if (to instanceof PublicKey) {
879 to = to.toAddress();
880 } else if (_.isString(to)) {
881 to = new Address(to);
882 }
883 var s = new Script();
884 s.add(Opcode.OP_DUP)
885 .add(Opcode.OP_HASH160)
886 .add(to.hashBuffer)
887 .add(Opcode.OP_EQUALVERIFY)
888 .add(Opcode.OP_CHECKSIG);
889 s._network = to.network;
890 return s;
891};
892
893/**
894 * @returns {Script} a new pay to witness v0 output for the given
895 * address
896 * @param {(Address|PublicKey)} to - destination address
897 */
898Script.buildWitnessV0Out = function(to) {
899 $.checkArgument(!_.isUndefined(to));
900 $.checkArgument(to instanceof PublicKey || to instanceof Address || _.isString(to));
901 if (to instanceof PublicKey) {
902 to = to.toAddress(null, Address.PayToWitnessPublicKeyHash);
903 } else if (_.isString(to)) {
904 to = new Address(to);
905 }
906 var s = new Script();
907 s.add(Opcode.OP_0)
908 .add(to.hashBuffer);
909 s._network = to.network;
910 return s;
911};
912
913/**
914 * @returns {Script} a new pay to public key output for the given
915 * public key
916 */
917Script.buildPublicKeyOut = function(pubkey) {
918 $.checkArgument(pubkey instanceof PublicKey);
919 var s = new Script();
920 s.add(pubkey.toBuffer())
921 .add(Opcode.OP_CHECKSIG);
922 return s;
923};
924
925/**
926 * @returns {Script} a new OP_RETURN script with data
927 * @param {(string|Buffer)} data - the data to embed in the output
928 * @param {(string)} encoding - the type of encoding of the string
929 */
930Script.buildDataOut = function(data, encoding) {
931 $.checkArgument(_.isUndefined(data) || _.isString(data) || BufferUtil.isBuffer(data));
932 if (_.isString(data)) {
933 data = Buffer.from(data, encoding);
934 }
935 var s = new Script();
936 s.add(Opcode.OP_RETURN);
937 if (!_.isUndefined(data)) {
938 s.add(data);
939 }
940 return s;
941};
942
943/**
944 * @param {Script|Address} script - the redeemScript for the new p2sh output.
945 * It can also be a p2sh address
946 * @returns {Script} new pay to script hash script for given script
947 */
948Script.buildScriptHashOut = function(script) {
949 $.checkArgument(script instanceof Script ||
950 (script instanceof Address && script.isPayToScriptHash()));
951 var s = new Script();
952 s.add(Opcode.OP_HASH160)
953 .add(script instanceof Address ? script.hashBuffer : Hash.sha256ripemd160(script.toBuffer()))
954 .add(Opcode.OP_EQUAL);
955
956 s._network = script._network || script.network;
957 return s;
958};
959
960/**
961 * Builds a scriptSig (a script for an input) that signs a public key output script.
962 *
963 * @param {Signature|Buffer} signature - a Signature object, or the signature in DER canonical encoding
964 * @param {number=} sigtype - the type of the signature (defaults to SIGHASH_ALL)
965 */
966Script.buildPublicKeyIn = function(signature, sigtype) {
967 $.checkArgument(signature instanceof Signature || BufferUtil.isBuffer(signature));
968 $.checkArgument(_.isUndefined(sigtype) || _.isNumber(sigtype));
969 if (signature instanceof Signature) {
970 signature = signature.toBuffer();
971 }
972 var script = new Script();
973 script.add(BufferUtil.concat([
974 signature,
975 BufferUtil.integerAsSingleByteBuffer(sigtype || Signature.SIGHASH_ALL)
976 ]));
977 return script;
978};
979
980/**
981 * Builds a scriptSig (a script for an input) that signs a public key hash
982 * output script.
983 *
984 * @param {Buffer|string|PublicKey} publicKey
985 * @param {Signature|Buffer} signature - a Signature object, or the signature in DER canonical encoding
986 * @param {number=} sigtype - the type of the signature (defaults to SIGHASH_ALL)
987 */
988Script.buildPublicKeyHashIn = function(publicKey, signature, sigtype) {
989 $.checkArgument(signature instanceof Signature || BufferUtil.isBuffer(signature));
990 $.checkArgument(_.isUndefined(sigtype) || _.isNumber(sigtype));
991 if (signature instanceof Signature) {
992 signature = signature.toBuffer();
993 }
994 var script = new Script()
995 .add(BufferUtil.concat([
996 signature,
997 BufferUtil.integerAsSingleByteBuffer(sigtype || Signature.SIGHASH_ALL)
998 ]))
999 .add(new PublicKey(publicKey).toBuffer());
1000 return script;
1001};
1002
1003/**
1004 * @returns {Script} an empty script
1005 */
1006Script.empty = function() {
1007 return new Script();
1008};
1009
1010/**
1011 * @returns {Script} a new pay to script hash script that pays to this script
1012 */
1013Script.prototype.toScriptHashOut = function() {
1014 return Script.buildScriptHashOut(this);
1015};
1016
1017/**
1018 * @return {Script} an output script built from the address
1019 */
1020Script.fromAddress = function(address) {
1021 address = Address(address);
1022 if (address.isPayToScriptHash()) {
1023 return Script.buildScriptHashOut(address);
1024 } else if (address.isPayToPublicKeyHash()) {
1025 return Script.buildPublicKeyHashOut(address);
1026 } else if (address.isPayToWitnessPublicKeyHash()) {
1027 return Script.buildWitnessV0Out(address);
1028 } else if (address.isPayToWitnessScriptHash()) {
1029 return Script.buildWitnessV0Out(address);
1030 }
1031 throw new errors.Script.UnrecognizedAddress(address);
1032};
1033
1034/**
1035 * Will return the associated address information object
1036 * @return {Address|boolean}
1037 */
1038Script.prototype.getAddressInfo = function(opts) {
1039 if (this._isInput) {
1040 return this._getInputAddressInfo();
1041 } else if (this._isOutput) {
1042 return this._getOutputAddressInfo();
1043 } else {
1044 var info = this._getOutputAddressInfo();
1045 if (!info) {
1046 return this._getInputAddressInfo();
1047 }
1048 return info;
1049 }
1050};
1051
1052/**
1053 * Will return the associated output scriptPubKey address information object
1054 * @return {Address|boolean}
1055 * @private
1056 */
1057Script.prototype._getOutputAddressInfo = function() {
1058 var info = {};
1059 if (this.isScriptHashOut()) {
1060 info.hashBuffer = this.getData();
1061 info.type = Address.PayToScriptHash;
1062 } else if (this.isPublicKeyHashOut()) {
1063 info.hashBuffer = this.getData();
1064 info.type = Address.PayToPublicKeyHash;
1065 } else if (this.isWitnessScriptHashOut()) {
1066 info.hashBuffer = this.getData();
1067 info.type = Address.PayToWitnessScriptHash;
1068 } else if (this.isWitnessPublicKeyHashOut()) {
1069 info.hashBuffer = this.getData();
1070 info.type = Address.PayToWitnessPublicKeyHash;
1071 } else if (this.isTaproot()) {
1072 info.hashBuffer = this.getData();
1073 info.type = Address.PayToTaproot;
1074 } else {
1075 return false;
1076 }
1077 return info;
1078};
1079
1080/**
1081 * Will return the associated input scriptSig address information object
1082 * @return {Address|boolean}
1083 * @private
1084 */
1085Script.prototype._getInputAddressInfo = function() {
1086 var info = {};
1087 if (this.isPublicKeyHashIn()) {
1088 // hash the publickey found in the scriptSig
1089 info.hashBuffer = Hash.sha256ripemd160(this.chunks[1].buf);
1090 info.type = Address.PayToPublicKeyHash;
1091 } else if (this.isScriptHashIn()) {
1092 // hash the redeemscript found at the end of the scriptSig
1093 info.hashBuffer = Hash.sha256ripemd160(this.chunks[this.chunks.length - 1].buf);
1094 info.type = Address.PayToScriptHash;
1095 } else {
1096 return false;
1097 }
1098 return info;
1099};
1100
1101/**
1102 * @param {Network=} network
1103 * @return {Address|boolean} the associated address for this script if possible, or false
1104 */
1105Script.prototype.toAddress = function(network) {
1106 var info = this.getAddressInfo();
1107 if (!info) {
1108 return false;
1109 }
1110 info.network = Networks.get(network) || this._network || Networks.defaultNetwork;
1111 return new Address(info);
1112};
1113
1114/**
1115 * Analogous to bitcoind's FindAndDelete. Find and delete equivalent chunks,
1116 * typically used with push data chunks. Note that this will find and delete
1117 * not just the same data, but the same data with the same push data op as
1118 * produced by default. i.e., if a pushdata in a tx does not use the minimal
1119 * pushdata op, then when you try to remove the data it is pushing, it will not
1120 * be removed, because they do not use the same pushdata op.
1121 */
1122Script.prototype.findAndDelete = function(script) {
1123 var buf = script.toBuffer();
1124 var hex = buf.toString('hex');
1125 for (var i = 0; i < this.chunks.length; i++) {
1126 var script2 = Script({
1127 chunks: [this.chunks[i]]
1128 });
1129 var buf2 = script2.toBuffer();
1130 var hex2 = buf2.toString('hex');
1131 if (hex === hex2) {
1132 this.chunks.splice(i, 1);
1133 }
1134 }
1135 return this;
1136};
1137
1138/**
1139 * Comes from bitcoind's script interpreter CheckMinimalPush function
1140 * @returns {boolean} if the chunk {i} is the smallest way to push that particular data.
1141 */
1142Script.prototype.checkMinimalPush = function(i) {
1143 var chunk = this.chunks[i];
1144 var buf = chunk.buf;
1145 var opcodenum = chunk.opcodenum;
1146 if (!buf) {
1147 return true;
1148 }
1149 if (buf.length === 0) {
1150 // Could have used OP_0.
1151 return opcodenum === Opcode.OP_0;
1152 } else if (buf.length === 1 && buf[0] >= 1 && buf[0] <= 16) {
1153 // Could have used OP_1 .. OP_16.
1154 return opcodenum === Opcode.OP_1 + (buf[0] - 1);
1155 } else if (buf.length === 1 && buf[0] === 0x81) {
1156 // Could have used OP_1NEGATE
1157 return opcodenum === Opcode.OP_1NEGATE;
1158 } else if (buf.length <= 75) {
1159 // Could have used a direct push (opcode indicating number of bytes pushed + those bytes).
1160 return opcodenum === buf.length;
1161 } else if (buf.length <= 255) {
1162 // Could have used OP_PUSHDATA.
1163 return opcodenum === Opcode.OP_PUSHDATA1;
1164 } else if (buf.length <= 65535) {
1165 // Could have used OP_PUSHDATA2.
1166 return opcodenum === Opcode.OP_PUSHDATA2;
1167 }
1168 return true;
1169};
1170
1171/**
1172 * Comes from bitcoind's script DecodeOP_N function
1173 * @param {number} opcode
1174 * @returns {number} numeric value in range of 0 to 16
1175 */
1176Script.prototype._decodeOP_N = function(opcode) {
1177 if (opcode === Opcode.OP_0) {
1178 return 0;
1179 } else if (opcode >= Opcode.OP_1 && opcode <= Opcode.OP_16) {
1180 return opcode - (Opcode.OP_1 - 1);
1181 } else {
1182 throw new Error('Invalid opcode: ' + JSON.stringify(opcode));
1183 }
1184};
1185
1186/**
1187 * Comes from bitcoind's script GetSigOpCount(boolean) function
1188 * @param {boolean} use current (true) or pre-version-0.6 (false) logic
1189 * @returns {number} number of signature operations required by this script
1190 */
1191Script.prototype.getSignatureOperationsCount = function(accurate) {
1192 accurate = (_.isUndefined(accurate) ? true : accurate);
1193 var self = this;
1194 var n = 0;
1195 var lastOpcode = Opcode.OP_INVALIDOPCODE;
1196 _.each(self.chunks, function getChunk(chunk) {
1197 var opcode = chunk.opcodenum;
1198 if (opcode == Opcode.OP_CHECKSIG || opcode == Opcode.OP_CHECKSIGVERIFY) {
1199 n++;
1200 } else if (opcode == Opcode.OP_CHECKMULTISIG || opcode == Opcode.OP_CHECKMULTISIGVERIFY) {
1201 if (accurate && lastOpcode >= Opcode.OP_1 && lastOpcode <= Opcode.OP_16) {
1202 n += self._decodeOP_N(lastOpcode);
1203 } else {
1204 n += 20;
1205 }
1206 }
1207 lastOpcode = opcode;
1208 });
1209 return n;
1210};
1211
1212module.exports = Script;