• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

handshake-org / hsd / 8452447998

27 Mar 2024 01:17PM UTC coverage: 16.226% (-52.4%) from 68.632%
8452447998

Pull #888

github

web-flow
Merge c40b9e40c into 0a4f24bdb
Pull Request #888: Wallet TX Count and time indexing

1001 of 12966 branches covered (7.72%)

Branch coverage included in aggregate %.

130 of 474 new or added lines in 11 files covered. (27.43%)

17522 existing lines in 124 files now uncovered.

6546 of 33547 relevant lines covered (19.51%)

37.41 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

8.01
/lib/script/script.js
1
/*!
2
 * script.js - script interpreter for hsd
3
 * Copyright (c) 2017-2018, Christopher Jeffrey (MIT License).
4
 * https://github.com/handshake-org/hsd
5
 */
6

7
'use strict';
8

9
const assert = require('bsert');
1✔
10
const bio = require('bufio');
1✔
11
const ripemd160 = require('bcrypto/lib/ripemd160');
1✔
12
const sha1 = require('bcrypto/lib/sha1');
1✔
13
const sha256 = require('bcrypto/lib/sha256');
1✔
14
const hash160 = require('bcrypto/lib/hash160');
1✔
15
const hash256 = require('bcrypto/lib/hash256');
1✔
16
const blake2b = require('bcrypto/lib/blake2b');
1✔
17
const sha3 = require('bcrypto/lib/sha3');
1✔
18
const keccak = require('bcrypto/lib/keccak');
1✔
19
const secp256k1 = require('bcrypto/lib/secp256k1');
1✔
20
const consensus = require('../protocol/consensus');
1✔
21
const Opcode = require('./opcode');
1✔
22
const Stack = require('./stack');
1✔
23
const ScriptError = require('./scripterror');
1✔
24
const ScriptNum = require('./scriptnum');
1✔
25
const common = require('./common');
1✔
26
const opcodes = common.opcodes;
1✔
27
const scriptTypes = common.types;
1✔
28
const {encoding} = bio;
1✔
29

30
/*
31
 * Constants
32
 */
33

34
const EMPTY_BUFFER = Buffer.alloc(0);
1✔
35

36
/**
37
 * Script
38
 * Represents a input or output script.
39
 * @alias module:script.Script
40
 * @property {Array} code - Parsed script code.
41
 * @property {Buffer?} raw - Serialized script.
42
 * @property {Number} length - Number of parsed opcodes.
43
 */
44

45
class Script extends bio.Struct {
46
  /**
47
   * Create a script.
48
   * @constructor
49
   * @param {Buffer|Array|Object} code
50
   */
51

52
  constructor(options) {
53
    super();
882✔
54

55
    this.raw = EMPTY_BUFFER;
882✔
56
    this.code = [];
882✔
57

58
    if (options)
882✔
59
      this.fromOptions(options);
3✔
60
  }
61

62
  /**
63
   * Get length.
64
   * @returns {Number}
65
   */
66

67
  get length() {
68
    return this.code.length;
×
69
  }
70

71
  /**
72
   * Set length.
73
   * @param {Number} value
74
   */
75

76
  set length(value) {
77
    this.code.length = value;
×
78
  }
79

80
  /**
81
   * Inject properties from options object.
82
   * @private
83
   * @param {Object} options
84
   */
85

86
  fromOptions(options) {
87
    assert(options, 'Script data is required.');
3✔
88

89
    if (Buffer.isBuffer(options))
3!
90
      return this.decode(options);
×
91

92
    if (Array.isArray(options))
3!
93
      return this.fromArray(options);
3✔
94

95
    if (options.raw) {
×
96
      if (!options.code)
×
97
        return this.decode(options.raw);
×
98
      assert(Buffer.isBuffer(options.raw), 'Raw must be a Buffer.');
×
99
      this.raw = options.raw;
×
100
    }
101

102
    if (options.code) {
×
103
      if (!options.raw)
×
104
        return this.fromArray(options.code);
×
105
      assert(Array.isArray(options.code), 'Code must be an array.');
×
106
      this.code = options.code;
×
107
    }
108

109
    return this;
×
110
  }
111

112
  /**
113
   * Instantiate a value-only iterator.
114
   * @returns {ScriptIterator}
115
   */
116

117
  values() {
118
    return this.code.values();
×
119
  }
120

121
  /**
122
   * Instantiate a key and value iterator.
123
   * @returns {ScriptIterator}
124
   */
125

126
  entries() {
127
    return this.code.entries();
×
128
  }
129

130
  /**
131
   * Instantiate a value-only iterator.
132
   * @returns {ScriptIterator}
133
   */
134

135
  [Symbol.iterator]() {
136
    return this.code[Symbol.iterator]();
×
137
  }
138

139
  /**
140
   * Convert the script to an array of
141
   * Buffers (pushdatas) and Numbers
142
   * (opcodes).
143
   * @returns {Array}
144
   */
145

146
  toArray() {
147
    return this.code.slice();
×
148
  }
149

150
  /**
151
   * Inject properties from an array of
152
   * of buffers and numbers.
153
   * @private
154
   * @param {Array} code
155
   * @returns {Script}
156
   */
157

158
  fromArray(code) {
159
    assert(Array.isArray(code));
3✔
160

161
    this.clear();
3✔
162

163
    for (const op of code)
3✔
164
      this.push(op);
7✔
165

166
    return this.compile();
3✔
167
  }
168

169
  /**
170
   * Instantiate script from an array
171
   * of buffers and numbers.
172
   * @param {Array} code
173
   * @returns {Script}
174
   */
175

176
  static fromArray(code) {
177
    return new this().fromArray(code);
×
178
  }
179

180
  /**
181
   * Convert script to stack items.
182
   * @returns {Buffer[]}
183
   */
184

185
  toItems() {
186
    const items = [];
×
187

188
    for (const op of this.code) {
×
189
      const data = op.toPush();
×
190

191
      if (!data)
×
192
        throw new Error('Non-push opcode in script.');
×
193

194
      items.push(data);
×
195
    }
196

197
    return items;
×
198
  }
199

200
  /**
201
   * Inject data from stack items.
202
   * @private
203
   * @param {Buffer[]} items
204
   * @returns {Script}
205
   */
206

207
  fromItems(items) {
208
    assert(Array.isArray(items));
×
209

210
    this.clear();
×
211

212
    for (const item of items)
×
213
      this.pushData(item);
×
214

215
    return this.compile();
×
216
  }
217

218
  /**
219
   * Instantiate script from stack items.
220
   * @param {Buffer[]} items
221
   * @returns {Script}
222
   */
223

224
  static fromItems(items) {
225
    return new this().fromItems(items);
×
226
  }
227

228
  /**
229
   * Convert script to stack.
230
   * @returns {Stack}
231
   */
232

233
  toStack() {
234
    return new Stack(this.toItems());
×
235
  }
236

237
  /**
238
   * Inject data from stack.
239
   * @private
240
   * @param {Stack} stack
241
   * @returns {Script}
242
   */
243

244
  fromStack(stack) {
245
    return this.fromItems(stack.items);
×
246
  }
247

248
  /**
249
   * Instantiate script from stack.
250
   * @param {Stack} stack
251
   * @returns {Script}
252
   */
253

254
  static fromStack(stack) {
255
    return new this().fromStack(stack);
×
256
  }
257

258
  /**
259
   * Inject properties from script.
260
   * Used for cloning.
261
   * @private
262
   * @param {Script} script
263
   * @returns {Script}
264
   */
265

266
  inject(script) {
UNCOV
267
    this.raw = script.raw;
×
UNCOV
268
    this.code = script.code.slice();
×
UNCOV
269
    return this;
×
270
  }
271

272
  /**
273
   * Test equality against script.
274
   * @param {Script} script
275
   * @returns {Boolean}
276
   */
277

278
  equals(script) {
279
    assert(Script.isScript(script));
×
280
    return this.raw.equals(script.raw);
×
281
  }
282

283
  /**
284
   * Compare against another script.
285
   * @param {Script} script
286
   * @returns {Number}
287
   */
288

289
  compare(script) {
290
    assert(Script.isScript(script));
×
291
    return this.raw.compare(script.raw);
×
292
  }
293

294
  /**
295
   * Clear the script.
296
   * @returns {Script}
297
   */
298

299
  clear() {
300
    this.raw = EMPTY_BUFFER;
3✔
301
    this.code.length = 0;
3✔
302
    return this;
3✔
303
  }
304

305
  /**
306
   * Inspect the script.
307
   * @returns {String} Human-readable script code.
308
   */
309

310
  format() {
311
    return `<Script: ${this.toString()}>`;
×
312
  }
313

314
  /**
315
   * Convert the script to a bitcoind test string.
316
   * @returns {String} Human-readable script code.
317
   */
318

319
  toString() {
320
    const out = [];
×
321

322
    for (const op of this.code)
×
323
      out.push(op.toFormat());
×
324

325
    return out.join(' ');
×
326
  }
327

328
  /**
329
   * Format the script as bitcoind asm.
330
   * @param {Boolean?} decode - Attempt to decode hash types.
331
   * @returns {String} Human-readable script.
332
   */
333

334
  toASM(decode) {
335
    const out = [];
×
336

337
    for (const op of this.code)
×
338
      out.push(op.toASM(decode));
×
339

340
    return out.join(' ');
×
341
  }
342

343
  /**
344
   * Re-encode the script internally. Useful if you
345
   * changed something manually in the `code` array.
346
   * @returns {Script}
347
   */
348

349
  compile() {
350
    if (this.code.length === 0)
4!
351
      return this.clear();
×
352

353
    let size = 0;
4✔
354

355
    for (const op of this.code)
4✔
356
      size += op.getSize();
112✔
357

358
    const bw = bio.write(size);
4✔
359

360
    for (const op of this.code)
4✔
361
      op.write(bw);
112✔
362

363
    this.raw = bw.render();
4✔
364

365
    return this;
4✔
366
  }
367

368
  /**
369
   * Write the script to a buffer writer.
370
   * @param {BufferWriter} bw
371
   */
372

373
  write(bw) {
374
    bw.writeVarBytes(this.raw);
×
375
    return bw;
×
376
  }
377

378
  /**
379
   * Encode the script to a Buffer. See {@link Script#encode}.
380
   * @param {String} enc - Encoding, either `'hex'` or `null`.
381
   * @returns {Buffer|String} Serialized script.
382
   */
383

384
  encode() {
385
    return this.raw;
1,757✔
386
  }
387

388
  /**
389
   * Convert script to a hex string.
390
   * @returns {String}
391
   */
392

393
  getJSON() {
394
    return this.toHex();
×
395
  }
396

397
  /**
398
   * Inject properties from json object.
399
   * @private
400
   * @param {String} json
401
   */
402

403
  fromJSON(json) {
404
    assert(typeof json === 'string', 'Code must be a string.');
×
405
    return this.decode(Buffer.from(json, 'hex'));
×
406
  }
407

408
  /**
409
   * Get the script's "subscript" starting at a separator.
410
   * @param {Number} index - The last separator to sign/verify beyond.
411
   * @returns {Script} Subscript.
412
   */
413

414
  getSubscript(index) {
UNCOV
415
    if (index === 0)
×
UNCOV
416
      return this.clone();
×
417

418
    const script = new Script();
×
419

420
    for (let i = index; i < this.code.length; i++) {
×
421
      const op = this.code[i];
×
422

423
      if (op.value === -1)
×
424
        break;
×
425

426
      script.code.push(op);
×
427
    }
428

429
    return script.compile();
×
430
  }
431

432
  /**
433
   * Get the script's "subscript" starting at a separator.
434
   * Remove all OP_CODESEPARATORs if present. This bizarre
435
   * behavior is necessary for signing and verification when
436
   * code separators are present.
437
   * @returns {Script} Subscript.
438
   */
439

440
  removeSeparators() {
441
    let found = false;
×
442

443
    // Optimizing for the common case:
444
    // Check for any separators first.
445
    for (const op of this.code) {
×
446
      if (op.value === -1)
×
447
        break;
×
448

449
      if (op.value === opcodes.OP_CODESEPARATOR) {
×
450
        found = true;
×
451
        break;
×
452
      }
453
    }
454

455
    if (!found)
×
456
      return this;
×
457

458
    // Uncommon case: someone actually
459
    // has a code separator. Go through
460
    // and remove them all.
461
    const script = new Script();
×
462

463
    for (const op of this.code) {
×
464
      if (op.value === -1)
×
465
        break;
×
466

467
      if (op.value !== opcodes.OP_CODESEPARATOR)
×
468
        script.code.push(op);
×
469
    }
470

471
    return script.compile();
×
472
  }
473

474
  /**
475
   * Execute and interpret the script.
476
   * @param {Stack} stack - Script execution stack.
477
   * @param {Number?} flags - Script standard flags.
478
   * @param {TX?} tx - Transaction being verified.
479
   * @param {Number?} index - Index of input being verified.
480
   * @param {Amount?} value - Previous output value.
481
   * @throws {ScriptError} Will be thrown on VERIFY failures.
482
   */
483

484
  execute(stack, flags, tx, index, value) {
UNCOV
485
    if (flags == null)
×
UNCOV
486
      flags = Script.flags.STANDARD_VERIFY_FLAGS;
×
487

UNCOV
488
    if (this.raw.length > consensus.MAX_SCRIPT_SIZE)
×
489
      throw new ScriptError('SCRIPT_SIZE');
×
490

UNCOV
491
    const state = [];
×
UNCOV
492
    const alt = [];
×
493

UNCOV
494
    let lastSep = 0;
×
UNCOV
495
    let opCount = 0;
×
UNCOV
496
    let negate = 0;
×
UNCOV
497
    let minimal = false;
×
498

UNCOV
499
    if (flags & Script.flags.VERIFY_MINIMALDATA)
×
UNCOV
500
      minimal = true;
×
501

UNCOV
502
    for (let ip = 0; ip < this.code.length; ip++) {
×
UNCOV
503
      const op = this.code[ip];
×
504

UNCOV
505
      if (op.value === -1)
×
506
        throw new ScriptError('BAD_OPCODE', op, ip);
×
507

UNCOV
508
      if (op.data && op.data.length > consensus.MAX_SCRIPT_PUSH)
×
UNCOV
509
        throw new ScriptError('PUSH_SIZE', op, ip);
×
510

UNCOV
511
      if (op.value > opcodes.OP_16 && ++opCount > consensus.MAX_SCRIPT_OPS)
×
UNCOV
512
        throw new ScriptError('OP_COUNT', op, ip);
×
513

UNCOV
514
      if (op.isDisabled())
×
UNCOV
515
        throw new ScriptError('DISABLED_OPCODE', op, ip);
×
516

UNCOV
517
      if (negate && !op.isBranch()) {
×
UNCOV
518
        if (stack.length + alt.length > consensus.MAX_SCRIPT_STACK)
×
519
          throw new ScriptError('STACK_SIZE', op, ip);
×
UNCOV
520
        continue;
×
521
      }
522

UNCOV
523
      if (op.data) {
×
UNCOV
524
        if (minimal && !op.isMinimal())
×
525
          throw new ScriptError('MINIMALDATA', op, ip);
×
526

UNCOV
527
        stack.push(op.data);
×
528

UNCOV
529
        if (stack.length + alt.length > consensus.MAX_SCRIPT_STACK)
×
530
          throw new ScriptError('STACK_SIZE', op, ip);
×
531

UNCOV
532
        continue;
×
533
      }
534

UNCOV
535
      switch (op.value) {
×
536
        case opcodes.OP_0: {
UNCOV
537
          stack.pushInt(0);
×
UNCOV
538
          break;
×
539
        }
540
        case opcodes.OP_1NEGATE: {
UNCOV
541
          stack.pushInt(-1);
×
UNCOV
542
          break;
×
543
        }
544
        case opcodes.OP_1:
545
        case opcodes.OP_2:
546
        case opcodes.OP_3:
547
        case opcodes.OP_4:
548
        case opcodes.OP_5:
549
        case opcodes.OP_6:
550
        case opcodes.OP_7:
551
        case opcodes.OP_8:
552
        case opcodes.OP_9:
553
        case opcodes.OP_10:
554
        case opcodes.OP_11:
555
        case opcodes.OP_12:
556
        case opcodes.OP_13:
557
        case opcodes.OP_14:
558
        case opcodes.OP_15:
559
        case opcodes.OP_16: {
UNCOV
560
          stack.pushInt(op.value - 0x50);
×
UNCOV
561
          break;
×
562
        }
563
        case opcodes.OP_NOP: {
UNCOV
564
          break;
×
565
        }
566
        case opcodes.OP_TYPE: {
UNCOV
567
          if (!tx)
×
568
            throw new ScriptError('UNKNOWN_ERROR', 'No TX passed in.');
×
569

UNCOV
570
          if (index >= tx.outputs.length) {
×
571
            stack.pushInt(0);
×
572
            break;
×
573
          }
574

UNCOV
575
          const {covenant} = tx.outputs[index];
×
576

UNCOV
577
          stack.pushInt(covenant.type);
×
578

UNCOV
579
          break;
×
580
        }
581
        case opcodes.OP_CHECKLOCKTIMEVERIFY: {
UNCOV
582
          if (!tx)
×
583
            throw new ScriptError('UNKNOWN_ERROR', 'No TX passed in.');
×
584

UNCOV
585
          if (stack.length === 0)
×
586
            throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
×
587

UNCOV
588
          const num = stack.getNum(-1, minimal, 5);
×
589

UNCOV
590
          if (num.isNeg())
×
UNCOV
591
            throw new ScriptError('NEGATIVE_LOCKTIME', op, ip);
×
592

UNCOV
593
          const locktime = num.toDouble();
×
594

UNCOV
595
          if (!tx.verifyLocktime(index, locktime))
×
UNCOV
596
            throw new ScriptError('UNSATISFIED_LOCKTIME', op, ip);
×
597

598
          break;
×
599
        }
600
        case opcodes.OP_CHECKSEQUENCEVERIFY: {
UNCOV
601
          if (!tx)
×
602
            throw new ScriptError('UNKNOWN_ERROR', 'No TX passed in.');
×
603

UNCOV
604
          if (stack.length === 0)
×
UNCOV
605
            throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
×
606

UNCOV
607
          const num = stack.getNum(-1, minimal, 5);
×
608

UNCOV
609
          if (num.isNeg())
×
UNCOV
610
            throw new ScriptError('NEGATIVE_LOCKTIME', op, ip);
×
611

UNCOV
612
          const locktime = num.toDouble();
×
613

UNCOV
614
          if (!tx.verifySequence(index, locktime))
×
UNCOV
615
            throw new ScriptError('UNSATISFIED_LOCKTIME', op, ip);
×
616

UNCOV
617
          break;
×
618
        }
619
        case opcodes.OP_NOP1:
620
        case opcodes.OP_NOP4:
621
        case opcodes.OP_NOP5:
622
        case opcodes.OP_NOP6:
623
        case opcodes.OP_NOP7:
624
        case opcodes.OP_NOP8:
625
        case opcodes.OP_NOP9:
626
        case opcodes.OP_NOP10: {
UNCOV
627
          if (flags & Script.flags.VERIFY_DISCOURAGE_UPGRADABLE_NOPS)
×
UNCOV
628
            throw new ScriptError('DISCOURAGE_UPGRADABLE_NOPS', op, ip);
×
UNCOV
629
          break;
×
630
        }
631
        case opcodes.OP_IF:
632
        case opcodes.OP_NOTIF: {
UNCOV
633
          let val = false;
×
634

UNCOV
635
          if (!negate) {
×
UNCOV
636
            if (stack.length < 1)
×
637
              throw new ScriptError('UNBALANCED_CONDITIONAL', op, ip);
×
638

UNCOV
639
            if (flags & Script.flags.VERIFY_MINIMALIF) {
×
UNCOV
640
              const item = stack.get(-1);
×
641

UNCOV
642
              if (item.length > 1)
×
UNCOV
643
                throw new ScriptError('MINIMALIF');
×
644

UNCOV
645
              if (item.length === 1 && item[0] !== 1)
×
UNCOV
646
                throw new ScriptError('MINIMALIF');
×
647
            }
648

UNCOV
649
            val = stack.getBool(-1);
×
650

UNCOV
651
            if (op.value === opcodes.OP_NOTIF)
×
UNCOV
652
              val = !val;
×
653

UNCOV
654
            stack.pop();
×
655
          }
656

UNCOV
657
          state.push(val);
×
658

UNCOV
659
          if (!val)
×
UNCOV
660
            negate += 1;
×
661

UNCOV
662
          break;
×
663
        }
664
        case opcodes.OP_ELSE: {
UNCOV
665
          if (state.length === 0)
×
UNCOV
666
            throw new ScriptError('UNBALANCED_CONDITIONAL', op, ip);
×
667

UNCOV
668
          state[state.length - 1] = !state[state.length - 1];
×
669

UNCOV
670
          if (!state[state.length - 1])
×
UNCOV
671
            negate += 1;
×
672
          else
UNCOV
673
            negate -= 1;
×
674

UNCOV
675
          break;
×
676
        }
677
        case opcodes.OP_ENDIF: {
UNCOV
678
          if (state.length === 0)
×
UNCOV
679
            throw new ScriptError('UNBALANCED_CONDITIONAL', op, ip);
×
680

UNCOV
681
          if (!state.pop())
×
UNCOV
682
            negate -= 1;
×
683

UNCOV
684
          break;
×
685
        }
686
        case opcodes.OP_VERIFY: {
UNCOV
687
          if (stack.length === 0)
×
688
            throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
×
689

UNCOV
690
          if (!stack.getBool(-1))
×
UNCOV
691
            throw new ScriptError('VERIFY', op, ip);
×
692

UNCOV
693
          stack.pop();
×
694

UNCOV
695
          break;
×
696
        }
697
        case opcodes.OP_RETURN: {
UNCOV
698
          throw new ScriptError('OP_RETURN', op, ip);
×
699
        }
700
        case opcodes.OP_TOALTSTACK: {
UNCOV
701
          if (stack.length === 0)
×
702
            throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
×
703

UNCOV
704
          alt.push(stack.pop());
×
UNCOV
705
          break;
×
706
        }
707
        case opcodes.OP_FROMALTSTACK: {
UNCOV
708
          if (alt.length === 0)
×
UNCOV
709
            throw new ScriptError('INVALID_ALTSTACK_OPERATION', op, ip);
×
710

UNCOV
711
          stack.push(alt.pop());
×
UNCOV
712
          break;
×
713
        }
714
        case opcodes.OP_2DROP: {
UNCOV
715
          if (stack.length < 2)
×
UNCOV
716
            throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
×
717

UNCOV
718
          stack.pop();
×
UNCOV
719
          stack.pop();
×
UNCOV
720
          break;
×
721
        }
722
        case opcodes.OP_2DUP: {
UNCOV
723
          if (stack.length < 2)
×
UNCOV
724
            throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
×
725

UNCOV
726
          const v1 = stack.get(-2);
×
UNCOV
727
          const v2 = stack.get(-1);
×
728

UNCOV
729
          stack.push(v1);
×
UNCOV
730
          stack.push(v2);
×
UNCOV
731
          break;
×
732
        }
733
        case opcodes.OP_3DUP: {
UNCOV
734
          if (stack.length < 3)
×
UNCOV
735
            throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
×
736

UNCOV
737
          const v1 = stack.get(-3);
×
UNCOV
738
          const v2 = stack.get(-2);
×
UNCOV
739
          const v3 = stack.get(-1);
×
740

UNCOV
741
          stack.push(v1);
×
UNCOV
742
          stack.push(v2);
×
UNCOV
743
          stack.push(v3);
×
UNCOV
744
          break;
×
745
        }
746
        case opcodes.OP_2OVER: {
UNCOV
747
          if (stack.length < 4)
×
UNCOV
748
            throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
×
749

UNCOV
750
          const v1 = stack.get(-4);
×
UNCOV
751
          const v2 = stack.get(-3);
×
752

UNCOV
753
          stack.push(v1);
×
UNCOV
754
          stack.push(v2);
×
UNCOV
755
          break;
×
756
        }
757
        case opcodes.OP_2ROT: {
UNCOV
758
          if (stack.length < 6)
×
UNCOV
759
            throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
×
760

UNCOV
761
          const v1 = stack.get(-6);
×
UNCOV
762
          const v2 = stack.get(-5);
×
763

UNCOV
764
          stack.erase(-6, -4);
×
UNCOV
765
          stack.push(v1);
×
UNCOV
766
          stack.push(v2);
×
UNCOV
767
          break;
×
768
        }
769
        case opcodes.OP_2SWAP: {
UNCOV
770
          if (stack.length < 4)
×
UNCOV
771
            throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
×
772

UNCOV
773
          stack.swap(-4, -2);
×
UNCOV
774
          stack.swap(-3, -1);
×
UNCOV
775
          break;
×
776
        }
777
        case opcodes.OP_IFDUP: {
UNCOV
778
          if (stack.length === 0)
×
779
            throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
×
780

UNCOV
781
          if (stack.getBool(-1)) {
×
UNCOV
782
            const val = stack.get(-1);
×
UNCOV
783
            stack.push(val);
×
784
          }
785

UNCOV
786
          break;
×
787
        }
788
        case opcodes.OP_DEPTH: {
UNCOV
789
          stack.pushInt(stack.length);
×
UNCOV
790
          break;
×
791
        }
792
        case opcodes.OP_DROP: {
UNCOV
793
          if (stack.length === 0)
×
794
            throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
×
795

UNCOV
796
          stack.pop();
×
UNCOV
797
          break;
×
798
        }
799
        case opcodes.OP_DUP: {
UNCOV
800
          if (stack.length === 0)
×
801
            throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
×
802

UNCOV
803
          stack.push(stack.get(-1));
×
UNCOV
804
          break;
×
805
        }
806
        case opcodes.OP_NIP: {
UNCOV
807
          if (stack.length < 2)
×
UNCOV
808
            throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
×
809

UNCOV
810
          stack.remove(-2);
×
UNCOV
811
          break;
×
812
        }
813
        case opcodes.OP_OVER: {
UNCOV
814
          if (stack.length < 2)
×
UNCOV
815
            throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
×
816

UNCOV
817
          stack.push(stack.get(-2));
×
UNCOV
818
          break;
×
819
        }
820
        case opcodes.OP_PICK:
821
        case opcodes.OP_ROLL: {
UNCOV
822
          if (stack.length < 2)
×
UNCOV
823
            throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
×
824

UNCOV
825
          const num = stack.getInt(-1, minimal, 4);
×
UNCOV
826
          stack.pop();
×
827

UNCOV
828
          if (num < 0 || num >= stack.length)
×
UNCOV
829
            throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
×
830

UNCOV
831
          const val = stack.get(-num - 1);
×
832

UNCOV
833
          if (op.value === opcodes.OP_ROLL)
×
UNCOV
834
            stack.remove(-num - 1);
×
835

UNCOV
836
          stack.push(val);
×
UNCOV
837
          break;
×
838
        }
839
        case opcodes.OP_ROT: {
UNCOV
840
          if (stack.length < 3)
×
UNCOV
841
            throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
×
842

UNCOV
843
          stack.swap(-3, -2);
×
UNCOV
844
          stack.swap(-2, -1);
×
UNCOV
845
          break;
×
846
        }
847
        case opcodes.OP_SWAP: {
UNCOV
848
          if (stack.length < 2)
×
UNCOV
849
            throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
×
850

UNCOV
851
          stack.swap(-2, -1);
×
UNCOV
852
          break;
×
853
        }
854
        case opcodes.OP_TUCK: {
UNCOV
855
          if (stack.length < 2)
×
UNCOV
856
            throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
×
857

UNCOV
858
          stack.insert(-2, stack.get(-1));
×
UNCOV
859
          break;
×
860
        }
861
        case opcodes.OP_SIZE: {
UNCOV
862
          if (stack.length < 1)
×
863
            throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
×
864

UNCOV
865
          stack.pushInt(stack.get(-1).length);
×
UNCOV
866
          break;
×
867
        }
868
        case opcodes.OP_EQUAL:
869
        case opcodes.OP_EQUALVERIFY: {
UNCOV
870
          if (stack.length < 2)
×
UNCOV
871
            throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
×
872

UNCOV
873
          const v1 = stack.get(-2);
×
UNCOV
874
          const v2 = stack.get(-1);
×
875

UNCOV
876
          const res = v1.equals(v2);
×
877

UNCOV
878
          stack.pop();
×
UNCOV
879
          stack.pop();
×
880

UNCOV
881
          stack.pushBool(res);
×
882

UNCOV
883
          if (op.value === opcodes.OP_EQUALVERIFY) {
×
UNCOV
884
            if (!res)
×
UNCOV
885
              throw new ScriptError('EQUALVERIFY', op, ip);
×
UNCOV
886
            stack.pop();
×
887
          }
888

UNCOV
889
          break;
×
890
        }
891
        case opcodes.OP_1ADD:
892
        case opcodes.OP_1SUB:
893
        case opcodes.OP_NEGATE:
894
        case opcodes.OP_ABS:
895
        case opcodes.OP_NOT:
896
        case opcodes.OP_0NOTEQUAL: {
UNCOV
897
          if (stack.length < 1)
×
898
            throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
×
899

UNCOV
900
          let num = stack.getNum(-1, minimal, 4);
×
901
          let cmp;
902

UNCOV
903
          switch (op.value) {
×
904
            case opcodes.OP_1ADD:
UNCOV
905
              num.iaddn(1);
×
UNCOV
906
              break;
×
907
            case opcodes.OP_1SUB:
UNCOV
908
              num.isubn(1);
×
UNCOV
909
              break;
×
910
            case opcodes.OP_NEGATE:
UNCOV
911
              num.ineg();
×
UNCOV
912
              break;
×
913
            case opcodes.OP_ABS:
UNCOV
914
              num.iabs();
×
UNCOV
915
              break;
×
916
            case opcodes.OP_NOT:
UNCOV
917
              cmp = num.isZero();
×
UNCOV
918
              num = ScriptNum.fromBool(cmp);
×
UNCOV
919
              break;
×
920
            case opcodes.OP_0NOTEQUAL:
UNCOV
921
              cmp = !num.isZero();
×
UNCOV
922
              num = ScriptNum.fromBool(cmp);
×
UNCOV
923
              break;
×
924
            default:
925
              assert(false, 'Fatal script error.');
×
926
              break;
×
927
          }
928

UNCOV
929
          stack.pop();
×
UNCOV
930
          stack.pushNum(num);
×
931

UNCOV
932
          break;
×
933
        }
934
        case opcodes.OP_ADD:
935
        case opcodes.OP_SUB:
936
        case opcodes.OP_BOOLAND:
937
        case opcodes.OP_BOOLOR:
938
        case opcodes.OP_NUMEQUAL:
939
        case opcodes.OP_NUMEQUALVERIFY:
940
        case opcodes.OP_NUMNOTEQUAL:
941
        case opcodes.OP_LESSTHAN:
942
        case opcodes.OP_GREATERTHAN:
943
        case opcodes.OP_LESSTHANOREQUAL:
944
        case opcodes.OP_GREATERTHANOREQUAL:
945
        case opcodes.OP_MIN:
946
        case opcodes.OP_MAX: {
UNCOV
947
          if (stack.length < 2)
×
UNCOV
948
            throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
×
949

UNCOV
950
          const n1 = stack.getNum(-2, minimal, 4);
×
UNCOV
951
          const n2 = stack.getNum(-1, minimal, 4);
×
952

953
          let num, cmp;
954

UNCOV
955
          switch (op.value) {
×
956
            case opcodes.OP_ADD:
UNCOV
957
              num = n1.iadd(n2);
×
UNCOV
958
              break;
×
959
            case opcodes.OP_SUB:
UNCOV
960
              num = n1.isub(n2);
×
UNCOV
961
              break;
×
962
            case opcodes.OP_BOOLAND:
UNCOV
963
              cmp = n1.toBool() && n2.toBool();
×
UNCOV
964
              num = ScriptNum.fromBool(cmp);
×
UNCOV
965
              break;
×
966
            case opcodes.OP_BOOLOR:
UNCOV
967
              cmp = n1.toBool() || n2.toBool();
×
UNCOV
968
              num = ScriptNum.fromBool(cmp);
×
UNCOV
969
              break;
×
970
            case opcodes.OP_NUMEQUAL:
UNCOV
971
              cmp = n1.eq(n2);
×
UNCOV
972
              num = ScriptNum.fromBool(cmp);
×
UNCOV
973
              break;
×
974
            case opcodes.OP_NUMEQUALVERIFY:
UNCOV
975
              cmp = n1.eq(n2);
×
UNCOV
976
              num = ScriptNum.fromBool(cmp);
×
UNCOV
977
              break;
×
978
            case opcodes.OP_NUMNOTEQUAL:
UNCOV
979
              cmp = !n1.eq(n2);
×
UNCOV
980
              num = ScriptNum.fromBool(cmp);
×
UNCOV
981
              break;
×
982
            case opcodes.OP_LESSTHAN:
UNCOV
983
              cmp = n1.lt(n2);
×
UNCOV
984
              num = ScriptNum.fromBool(cmp);
×
UNCOV
985
              break;
×
986
            case opcodes.OP_GREATERTHAN:
UNCOV
987
              cmp = n1.gt(n2);
×
UNCOV
988
              num = ScriptNum.fromBool(cmp);
×
UNCOV
989
              break;
×
990
            case opcodes.OP_LESSTHANOREQUAL:
UNCOV
991
              cmp = n1.lte(n2);
×
UNCOV
992
              num = ScriptNum.fromBool(cmp);
×
UNCOV
993
              break;
×
994
            case opcodes.OP_GREATERTHANOREQUAL:
UNCOV
995
              cmp = n1.gte(n2);
×
UNCOV
996
              num = ScriptNum.fromBool(cmp);
×
UNCOV
997
              break;
×
998
            case opcodes.OP_MIN:
UNCOV
999
              num = ScriptNum.min(n1, n2);
×
UNCOV
1000
              break;
×
1001
            case opcodes.OP_MAX:
UNCOV
1002
              num = ScriptNum.max(n1, n2);
×
UNCOV
1003
              break;
×
1004
            default:
1005
              assert(false, 'Fatal script error.');
×
1006
              break;
×
1007
          }
1008

UNCOV
1009
          stack.pop();
×
UNCOV
1010
          stack.pop();
×
UNCOV
1011
          stack.pushNum(num);
×
1012

UNCOV
1013
          if (op.value === opcodes.OP_NUMEQUALVERIFY) {
×
UNCOV
1014
            if (!stack.getBool(-1))
×
1015
              throw new ScriptError('NUMEQUALVERIFY', op, ip);
×
UNCOV
1016
            stack.pop();
×
1017
          }
1018

UNCOV
1019
          break;
×
1020
        }
1021
        case opcodes.OP_WITHIN: {
UNCOV
1022
          if (stack.length < 3)
×
UNCOV
1023
            throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
×
1024

UNCOV
1025
          const n1 = stack.getNum(-3, minimal, 4);
×
UNCOV
1026
          const n2 = stack.getNum(-2, minimal, 4);
×
UNCOV
1027
          const n3 = stack.getNum(-1, minimal, 4);
×
1028

UNCOV
1029
          const val = n2.lte(n1) && n1.lt(n3);
×
1030

UNCOV
1031
          stack.pop();
×
UNCOV
1032
          stack.pop();
×
UNCOV
1033
          stack.pop();
×
1034

UNCOV
1035
          stack.pushBool(val);
×
UNCOV
1036
          break;
×
1037
        }
1038
        case opcodes.OP_RIPEMD160: {
UNCOV
1039
          if (stack.length === 0)
×
1040
            throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
×
1041

UNCOV
1042
          stack.push(ripemd160.digest(stack.pop()));
×
UNCOV
1043
          break;
×
1044
        }
1045
        case opcodes.OP_SHA1: {
UNCOV
1046
          if (stack.length === 0)
×
1047
            throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
×
1048

UNCOV
1049
          stack.push(sha1.digest(stack.pop()));
×
UNCOV
1050
          break;
×
1051
        }
1052
        case opcodes.OP_SHA256: {
UNCOV
1053
          if (stack.length === 0)
×
1054
            throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
×
1055

UNCOV
1056
          stack.push(sha256.digest(stack.pop()));
×
UNCOV
1057
          break;
×
1058
        }
1059
        case opcodes.OP_HASH160: {
UNCOV
1060
          if (stack.length === 0)
×
1061
            throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
×
1062

UNCOV
1063
          stack.push(hash160.digest(stack.pop()));
×
UNCOV
1064
          break;
×
1065
        }
1066
        case opcodes.OP_HASH256: {
UNCOV
1067
          if (stack.length === 0)
×
1068
            throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
×
1069

UNCOV
1070
          stack.push(hash256.digest(stack.pop()));
×
UNCOV
1071
          break;
×
1072
        }
1073
        case opcodes.OP_BLAKE160: {
UNCOV
1074
          if (stack.length === 0)
×
UNCOV
1075
            throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
×
1076

UNCOV
1077
          stack.push(blake2b.digest(stack.pop(), 20));
×
UNCOV
1078
          break;
×
1079
        }
1080
        case opcodes.OP_BLAKE256: {
UNCOV
1081
          if (stack.length === 0)
×
UNCOV
1082
            throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
×
1083

1084
          stack.push(blake2b.digest(stack.pop()));
×
1085
          break;
×
1086
        }
1087
        case opcodes.OP_SHA3: {
UNCOV
1088
          if (stack.length === 0)
×
UNCOV
1089
            throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
×
1090

1091
          stack.push(sha3.digest(stack.pop()));
×
1092
          break;
×
1093
        }
1094
        case opcodes.OP_KECCAK: {
UNCOV
1095
          if (stack.length === 0)
×
UNCOV
1096
            throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
×
1097

1098
          stack.push(keccak.digest(stack.pop()));
×
1099
          break;
×
1100
        }
1101
        case opcodes.OP_CODESEPARATOR: {
1102
          lastSep = ip + 1;
×
1103
          break;
×
1104
        }
1105
        case opcodes.OP_CHECKSIG:
1106
        case opcodes.OP_CHECKSIGVERIFY: {
UNCOV
1107
          if (!tx)
×
1108
            throw new ScriptError('UNKNOWN_ERROR', 'No TX passed in.');
×
1109

UNCOV
1110
          if (stack.length < 2)
×
UNCOV
1111
            throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
×
1112

UNCOV
1113
          const sig = stack.get(-2);
×
UNCOV
1114
          const key = stack.get(-1);
×
1115

UNCOV
1116
          const subscript = this.getSubscript(lastSep);
×
1117

UNCOV
1118
          validateSignature(sig, flags);
×
UNCOV
1119
          validateKey(key, flags);
×
1120

UNCOV
1121
          let res = false;
×
1122

UNCOV
1123
          if (sig.length > 0) {
×
UNCOV
1124
            const type = sig[sig.length - 1];
×
UNCOV
1125
            const hash = tx.signatureHash(
×
1126
              index,
1127
              subscript,
1128
              value,
1129
              type
1130
            );
UNCOV
1131
            res = checksig(hash, sig, key);
×
1132
          }
1133

UNCOV
1134
          if (!res && (flags & Script.flags.VERIFY_NULLFAIL)) {
×
UNCOV
1135
            if (sig.length !== 0)
×
UNCOV
1136
              throw new ScriptError('NULLFAIL', op, ip);
×
1137
          }
1138

UNCOV
1139
          stack.pop();
×
UNCOV
1140
          stack.pop();
×
1141

UNCOV
1142
          stack.pushBool(res);
×
1143

UNCOV
1144
          if (op.value === opcodes.OP_CHECKSIGVERIFY) {
×
1145
            if (!res)
×
1146
              throw new ScriptError('CHECKSIGVERIFY', op, ip);
×
1147
            stack.pop();
×
1148
          }
1149

UNCOV
1150
          break;
×
1151
        }
1152
        case opcodes.OP_CHECKMULTISIG:
1153
        case opcodes.OP_CHECKMULTISIGVERIFY: {
UNCOV
1154
          if (!tx)
×
1155
            throw new ScriptError('UNKNOWN_ERROR', 'No TX passed in.');
×
1156

UNCOV
1157
          let i = 1;
×
UNCOV
1158
          if (stack.length < i)
×
UNCOV
1159
            throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
×
1160

UNCOV
1161
          let n = stack.getInt(-i, minimal, 4);
×
UNCOV
1162
          let okey = n + 2;
×
1163
          let ikey, isig;
1164

UNCOV
1165
          if (n < 0 || n > consensus.MAX_MULTISIG_PUBKEYS)
×
UNCOV
1166
            throw new ScriptError('PUBKEY_COUNT', op, ip);
×
1167

UNCOV
1168
          opCount += n;
×
1169

UNCOV
1170
          if (opCount > consensus.MAX_SCRIPT_OPS)
×
UNCOV
1171
            throw new ScriptError('OP_COUNT', op, ip);
×
1172

UNCOV
1173
          i += 1;
×
UNCOV
1174
          ikey = i;
×
UNCOV
1175
          i += n;
×
1176

UNCOV
1177
          if (stack.length < i)
×
UNCOV
1178
            throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
×
1179

UNCOV
1180
          let m = stack.getInt(-i, minimal, 4);
×
1181

UNCOV
1182
          if (m < 0 || m > n)
×
UNCOV
1183
            throw new ScriptError('SIG_COUNT', op, ip);
×
1184

UNCOV
1185
          i += 1;
×
UNCOV
1186
          isig = i;
×
UNCOV
1187
          i += m;
×
1188

UNCOV
1189
          if (stack.length < i)
×
UNCOV
1190
            throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
×
1191

UNCOV
1192
          const subscript = this.getSubscript(lastSep);
×
1193

UNCOV
1194
          let res = true;
×
UNCOV
1195
          while (res && m > 0) {
×
UNCOV
1196
            const sig = stack.get(-isig);
×
UNCOV
1197
            const key = stack.get(-ikey);
×
1198

UNCOV
1199
            validateSignature(sig, flags);
×
UNCOV
1200
            validateKey(key, flags);
×
1201

UNCOV
1202
            if (sig.length > 0) {
×
UNCOV
1203
              const type = sig[sig.length - 1];
×
UNCOV
1204
              const hash = tx.signatureHash(
×
1205
                index,
1206
                subscript,
1207
                value,
1208
                type
1209
              );
1210

UNCOV
1211
              if (checksig(hash, sig, key)) {
×
UNCOV
1212
                isig += 1;
×
UNCOV
1213
                m -= 1;
×
1214
              }
1215
            }
1216

UNCOV
1217
            ikey += 1;
×
UNCOV
1218
            n -= 1;
×
1219

UNCOV
1220
            if (m > n)
×
UNCOV
1221
              res = false;
×
1222
          }
1223

UNCOV
1224
          while (i > 1) {
×
UNCOV
1225
            if (!res && (flags & Script.flags.VERIFY_NULLFAIL)) {
×
UNCOV
1226
              if (okey === 0 && stack.get(-1).length !== 0)
×
UNCOV
1227
                throw new ScriptError('NULLFAIL', op, ip);
×
1228
            }
1229

UNCOV
1230
            if (okey > 0)
×
UNCOV
1231
              okey -= 1;
×
1232

UNCOV
1233
            stack.pop();
×
1234

UNCOV
1235
            i -= 1;
×
1236
          }
1237

UNCOV
1238
          if (stack.length < 1)
×
1239
            throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
×
1240

UNCOV
1241
          if (stack.get(-1).length !== 0)
×
UNCOV
1242
            throw new ScriptError('SIG_NULLDUMMY', op, ip);
×
1243

UNCOV
1244
          stack.pop();
×
1245

UNCOV
1246
          stack.pushBool(res);
×
1247

UNCOV
1248
          if (op.value === opcodes.OP_CHECKMULTISIGVERIFY) {
×
UNCOV
1249
            if (!res)
×
1250
              throw new ScriptError('CHECKMULTISIGVERIFY', op, ip);
×
UNCOV
1251
            stack.pop();
×
1252
          }
1253

UNCOV
1254
          break;
×
1255
        }
1256
        default: {
UNCOV
1257
          throw new ScriptError('BAD_OPCODE', op, ip);
×
1258
        }
1259
      }
1260

UNCOV
1261
      if (stack.length + alt.length > consensus.MAX_SCRIPT_STACK)
×
1262
        throw new ScriptError('STACK_SIZE', op, ip);
×
1263
    }
1264

UNCOV
1265
    if (state.length !== 0)
×
UNCOV
1266
      throw new ScriptError('UNBALANCED_CONDITIONAL');
×
1267
  }
1268

1269
  /**
1270
   * Find a data element in a script.
1271
   * @param {Buffer} data - Data element to match against.
1272
   * @returns {Number} Index (`-1` if not present).
1273
   */
1274

1275
  indexOf(data) {
UNCOV
1276
    for (let i = 0; i < this.code.length; i++) {
×
UNCOV
1277
      const op = this.code[i];
×
1278

UNCOV
1279
      if (op.value === -1)
×
1280
        break;
×
1281

UNCOV
1282
      if (!op.data)
×
UNCOV
1283
        continue;
×
1284

UNCOV
1285
      if (op.data.equals(data))
×
UNCOV
1286
        return i;
×
1287
    }
1288

1289
    return -1;
×
1290
  }
1291

1292
  /**
1293
   * Test a script to see if it is likely
1294
   * to be script code (no weird opcodes).
1295
   * @returns {Boolean}
1296
   */
1297

1298
  isCode() {
1299
    for (const op of this.code) {
×
1300
      if (op.value === -1)
×
1301
        return false;
×
1302

1303
      if (op.isDisabled())
×
1304
        return false;
×
1305

1306
      switch (op.value) {
×
1307
        case opcodes.OP_RESERVED:
1308
        case opcodes.OP_NOP:
1309
        case opcodes.OP_VER:
1310
        case opcodes.OP_VERIF:
1311
        case opcodes.OP_VERNOTIF:
1312
        case opcodes.OP_RESERVED1:
1313
        case opcodes.OP_RESERVED2:
1314
          return false;
×
1315
      }
1316

1317
      if (op.value > opcodes.OP_CHECKSEQUENCEVERIFY)
×
1318
        return false;
×
1319
    }
1320

1321
    return true;
×
1322
  }
1323

1324
  /**
1325
   * Inject properties from a pay-to-pubkey script.
1326
   * @private
1327
   * @param {Buffer} key
1328
   */
1329

1330
  fromPubkey(key) {
1331
    assert(Buffer.isBuffer(key) && key.length === 33);
×
1332

1333
    this.raw = Buffer.allocUnsafe(35);
×
1334
    this.raw[0] = 33;
×
1335
    key.copy(this.raw, 1);
×
1336
    this.raw[34] = opcodes.OP_CHECKSIG;
×
1337

1338
    key = this.raw.slice(1, 34);
×
1339

1340
    this.code.length = 0;
×
1341
    this.code.push(Opcode.fromPush(key));
×
1342
    this.code.push(Opcode.fromOp(opcodes.OP_CHECKSIG));
×
1343

1344
    return this;
×
1345
  }
1346

1347
  /**
1348
   * Create a pay-to-pubkey script.
1349
   * @param {Buffer} key
1350
   * @returns {Script}
1351
   */
1352

1353
  static fromPubkey(key) {
1354
    return new this().fromPubkey(key);
×
1355
  }
1356

1357
  /**
1358
   * Inject properties from a pay-to-pubkeyhash script.
1359
   * @private
1360
   * @param {Buffer} hash
1361
   */
1362

1363
  fromPubkeyhash(hash) {
1364
    assert(Buffer.isBuffer(hash) && hash.length === 20);
1✔
1365

1366
    this.raw = Buffer.allocUnsafe(25);
1✔
1367
    this.raw[0] = opcodes.OP_DUP;
1✔
1368
    this.raw[1] = opcodes.OP_BLAKE160;
1✔
1369
    this.raw[2] = 0x14;
1✔
1370
    hash.copy(this.raw, 3);
1✔
1371
    this.raw[23] = opcodes.OP_EQUALVERIFY;
1✔
1372
    this.raw[24] = opcodes.OP_CHECKSIG;
1✔
1373

1374
    hash = this.raw.slice(3, 23);
1✔
1375

1376
    this.code.length = 0;
1✔
1377
    this.code.push(Opcode.fromOp(opcodes.OP_DUP));
1✔
1378
    this.code.push(Opcode.fromOp(opcodes.OP_BLAKE160));
1✔
1379
    this.code.push(Opcode.fromPush(hash));
1✔
1380
    this.code.push(Opcode.fromOp(opcodes.OP_EQUALVERIFY));
1✔
1381
    this.code.push(Opcode.fromOp(opcodes.OP_CHECKSIG));
1✔
1382

1383
    return this;
1✔
1384
  }
1385

1386
  /**
1387
   * Create a pay-to-pubkeyhash script.
1388
   * @param {Buffer} hash
1389
   * @returns {Script}
1390
   */
1391

1392
  static fromPubkeyhash(hash) {
1393
    return new this().fromPubkeyhash(hash);
1✔
1394
  }
1395

1396
  /**
1397
   * Inject properties from pay-to-multisig script.
1398
   * @private
1399
   * @param {Number} m
1400
   * @param {Number} n
1401
   * @param {Buffer[]} keys
1402
   */
1403

1404
  fromMultisig(m, n, keys) {
UNCOV
1405
    assert((m & 0xff) === m && (n & 0xff) === n);
×
UNCOV
1406
    assert(Array.isArray(keys));
×
UNCOV
1407
    assert(keys.length === n, '`n` keys are required for multisig.');
×
UNCOV
1408
    assert(m >= 1 && m <= n);
×
UNCOV
1409
    assert(n >= 1 && n <= 15);
×
1410

UNCOV
1411
    this.clear();
×
1412

UNCOV
1413
    this.pushSmall(m);
×
1414

UNCOV
1415
    for (const key of sortKeys(keys))
×
UNCOV
1416
      this.pushData(key);
×
1417

UNCOV
1418
    this.pushSmall(n);
×
UNCOV
1419
    this.pushOp(opcodes.OP_CHECKMULTISIG);
×
1420

UNCOV
1421
    return this.compile();
×
1422
  }
1423

1424
  /**
1425
   * Create a pay-to-multisig script.
1426
   * @param {Number} m
1427
   * @param {Number} n
1428
   * @param {Buffer[]} keys
1429
   * @returns {Script}
1430
   */
1431

1432
  static fromMultisig(m, n, keys) {
UNCOV
1433
    return new this().fromMultisig(m, n, keys);
×
1434
  }
1435

1436
  /**
1437
   * Get the standard script type.
1438
   * @returns {ScriptType}
1439
   */
1440

1441
  getType() {
1442
    if (this.isPubkey())
×
1443
      return scriptTypes.PUBKEY;
×
1444

1445
    if (this.isPubkeyhash())
×
1446
      return scriptTypes.PUBKEYHASH;
×
1447

1448
    if (this.isMultisig())
×
1449
      return scriptTypes.MULTISIG;
×
1450

1451
    return scriptTypes.NONSTANDARD;
×
1452
  }
1453

1454
  /**
1455
   * Test whether a script is of an unknown/non-standard type.
1456
   * @returns {Boolean}
1457
   */
1458

1459
  isUnknown() {
1460
    return this.getType() === scriptTypes.NONSTANDARD;
×
1461
  }
1462

1463
  /**
1464
   * Test whether the script is standard by policy standards.
1465
   * @returns {Boolean}
1466
   */
1467

1468
  isStandard() {
1469
    const [m, n] = this.getMultisig();
×
1470

1471
    if (m !== -1) {
×
1472
      if (n < 1 || n > 3)
×
1473
        return false;
×
1474

1475
      if (m < 1 || m > n)
×
1476
        return false;
×
1477

1478
      return true;
×
1479
    }
1480

1481
    return this.getType() !== scriptTypes.NONSTANDARD;
×
1482
  }
1483

1484
  /**
1485
   * Calculate the size of the script
1486
   * excluding the varint size bytes.
1487
   * @returns {Number}
1488
   */
1489

1490
  getSize() {
1491
    return this.raw.length;
×
1492
  }
1493

1494
  /**
1495
   * Calculate the size of the script
1496
   * including the varint size bytes.
1497
   * @returns {Number}
1498
   */
1499

1500
  getVarSize() {
UNCOV
1501
    return encoding.sizeVarBytes(this.raw);
×
1502
  }
1503

1504
  /**
1505
   * Get the sha3 of the raw script.
1506
   * @returns {Hash}
1507
   */
1508

1509
  sha3() {
1510
    return sha3.digest(this.encode());
3✔
1511
  }
1512

1513
  /**
1514
   * Test whether the output script is pay-to-pubkey.
1515
   * @param {Boolean} [minimal=false] - Minimaldata only.
1516
   * @returns {Boolean}
1517
   */
1518

1519
  isPubkey(minimal) {
UNCOV
1520
    if (minimal) {
×
1521
      return this.raw.length === 35
×
1522
        && this.raw[0] === 33
1523
        && this.raw[0] + 2 === this.raw.length
1524
        && this.raw[this.raw.length - 1] === opcodes.OP_CHECKSIG;
1525
    }
1526

UNCOV
1527
    if (this.code.length !== 2)
×
UNCOV
1528
      return false;
×
1529

1530
    return this.getLength(0) === 33
×
1531
      && this.getOp(1) === opcodes.OP_CHECKSIG;
1532
  }
1533

1534
  /**
1535
   * Get P2PK key if present.
1536
   * @param {Boolean} [minimal=false] - Minimaldata only.
1537
   * @returns {Buffer|null}
1538
   */
1539

1540
  getPubkey(minimal) {
UNCOV
1541
    if (!this.isPubkey(minimal))
×
UNCOV
1542
      return null;
×
1543

1544
    if (minimal)
×
1545
      return this.raw.slice(1, 1 + this.raw[0]);
×
1546

1547
    return this.getData(0);
×
1548
  }
1549

1550
  /**
1551
   * Test whether the output script is pay-to-pubkeyhash.
1552
   * @param {Boolean} [minimal=false] - Minimaldata only.
1553
   * @returns {Boolean}
1554
   */
1555

1556
  isPubkeyhash(minimal) {
UNCOV
1557
    if (minimal || this.raw.length === 25) {
×
UNCOV
1558
      return this.raw.length === 25
×
1559
        && this.raw[0] === opcodes.OP_DUP
1560
        && this.raw[1] === opcodes.OP_BLAKE160
1561
        && this.raw[2] === 0x14
1562
        && this.raw[23] === opcodes.OP_EQUALVERIFY
1563
        && this.raw[24] === opcodes.OP_CHECKSIG;
1564
    }
1565

UNCOV
1566
    if (this.code.length !== 5)
×
UNCOV
1567
      return false;
×
1568

UNCOV
1569
    return this.getOp(0) === opcodes.OP_DUP
×
1570
      && this.getOp(1) === opcodes.OP_BLAKE160
1571
      && this.getLength(2) === 20
1572
      && this.getOp(3) === opcodes.OP_EQUALVERIFY
1573
      && this.getOp(4) === opcodes.OP_CHECKSIG;
1574
  }
1575

1576
  /**
1577
   * Get P2PKH hash if present.
1578
   * @param {Boolean} [minimal=false] - Minimaldata only.
1579
   * @returns {Buffer|null}
1580
   */
1581

1582
  getPubkeyhash(minimal) {
UNCOV
1583
    if (!this.isPubkeyhash(minimal))
×
UNCOV
1584
      return null;
×
1585

UNCOV
1586
    if (minimal)
×
1587
      return this.raw.slice(3, 23);
×
1588

UNCOV
1589
    return this.getData(2);
×
1590
  }
1591

1592
  /**
1593
   * Test whether the output script is pay-to-multisig.
1594
   * @param {Boolean} [minimal=false] - Minimaldata only.
1595
   * @returns {Boolean}
1596
   */
1597

1598
  isMultisig(minimal) {
UNCOV
1599
    if (this.code.length < 4 || this.code.length > 19)
×
1600
      return false;
×
1601

UNCOV
1602
    if (this.getOp(-1) !== opcodes.OP_CHECKMULTISIG)
×
1603
      return false;
×
1604

UNCOV
1605
    const m = this.getSmall(0);
×
1606

UNCOV
1607
    if (m < 1)
×
1608
      return false;
×
1609

UNCOV
1610
    const n = this.getSmall(-2);
×
1611

UNCOV
1612
    if (n < 1 || m > n)
×
1613
      return false;
×
1614

UNCOV
1615
    if (this.code.length !== n + 3)
×
1616
      return false;
×
1617

UNCOV
1618
    for (let i = 1; i < n + 1; i++) {
×
UNCOV
1619
      const op = this.code[i];
×
1620

UNCOV
1621
      if (op.toLength() !== 33)
×
1622
        return false;
×
1623

UNCOV
1624
      if (minimal && !op.isMinimal())
×
1625
        return false;
×
1626
    }
1627

UNCOV
1628
    return true;
×
1629
  }
1630

1631
  /**
1632
   * Get multisig m and n values if present.
1633
   * @param {Boolean} [minimal=false] - Minimaldata only.
1634
   * @returns {Array} [m, n]
1635
   */
1636

1637
  getMultisig(minimal) {
UNCOV
1638
    if (!this.isMultisig(minimal))
×
1639
      return [-1, -1];
×
1640

UNCOV
1641
    return [this.getSmall(0), this.getSmall(-2)];
×
1642
  }
1643

1644
  /**
1645
   * Test whether the output script is unspendable.
1646
   * @returns {Boolean}
1647
   */
1648

1649
  isUnspendable() {
1650
    if (this.raw.length > consensus.MAX_SCRIPT_SIZE)
×
1651
      return true;
×
1652

1653
    return this.raw.length > 0 && this.raw[0] === opcodes.OP_RETURN;
×
1654
  }
1655

1656
  /**
1657
   * Test the script against a bloom filter.
1658
   * @param {Bloom} filter
1659
   * @returns {Boolean}
1660
   */
1661

1662
  test(filter) {
1663
    for (const op of this.code) {
×
1664
      if (op.value === -1)
×
1665
        break;
×
1666

1667
      if (!op.data || op.data.length === 0)
×
1668
        continue;
×
1669

1670
      if (filter.test(op.data))
×
1671
        return true;
×
1672
    }
1673

1674
    return false;
×
1675
  }
1676

1677
  /**
1678
   * Test the script to see if it contains only push ops.
1679
   * Push ops are: OP_1NEGATE, OP_0-OP_16 and all PUSHDATAs.
1680
   * @returns {Boolean}
1681
   */
1682

1683
  isPushOnly() {
1684
    for (const op of this.code) {
×
1685
      if (op.value === -1)
×
1686
        return false;
×
1687

1688
      if (op.value > opcodes.OP_16)
×
1689
        return false;
×
1690
    }
1691

1692
    return true;
×
1693
  }
1694

1695
  /**
1696
   * Count the sigops in the script.
1697
   * @returns {Number} sigop count
1698
   */
1699

1700
  getSigops() {
UNCOV
1701
    let total = 0;
×
UNCOV
1702
    let lastOp = -1;
×
1703

UNCOV
1704
    for (const op of this.code) {
×
UNCOV
1705
      if (op.value === -1)
×
1706
        break;
×
1707

UNCOV
1708
      switch (op.value) {
×
1709
        case opcodes.OP_CHECKSIG:
1710
        case opcodes.OP_CHECKSIGVERIFY:
UNCOV
1711
          total += 1;
×
UNCOV
1712
          break;
×
1713
        case opcodes.OP_CHECKMULTISIG:
1714
        case opcodes.OP_CHECKMULTISIGVERIFY:
UNCOV
1715
          if (lastOp >= opcodes.OP_1 && lastOp <= opcodes.OP_16)
×
UNCOV
1716
            total += lastOp - 0x50;
×
1717
          else
1718
            total += consensus.MAX_MULTISIG_PUBKEYS;
×
UNCOV
1719
          break;
×
1720
      }
1721

UNCOV
1722
      lastOp = op.value;
×
1723
    }
1724

UNCOV
1725
    return total;
×
1726
  }
1727

1728
  /*
1729
   * Mutation
1730
   */
1731

1732
  get(index) {
UNCOV
1733
    if (index < 0)
×
UNCOV
1734
      index += this.code.length;
×
1735

UNCOV
1736
    if (index < 0 || index >= this.code.length)
×
1737
      return null;
×
1738

UNCOV
1739
    return this.code[index];
×
1740
  }
1741

1742
  pop() {
1743
    const op = this.code.pop();
×
1744
    return op || null;
×
1745
  }
1746

1747
  shift() {
1748
    const op = this.code.shift();
×
1749
    return op || null;
×
1750
  }
1751

1752
  remove(index) {
1753
    if (index < 0)
×
1754
      index += this.code.length;
×
1755

1756
    if (index < 0 || index >= this.code.length)
×
1757
      return null;
×
1758

1759
    const items = this.code.splice(index, 1);
×
1760

1761
    if (items.length === 0)
×
1762
      return null;
×
1763

1764
    return items[0];
×
1765
  }
1766

1767
  set(index, op) {
1768
    if (index < 0)
×
1769
      index += this.code.length;
×
1770

1771
    assert(Opcode.isOpcode(op));
×
1772
    assert(index >= 0 && index <= this.code.length);
×
1773

1774
    this.code[index] = op;
×
1775

1776
    return this;
×
1777
  }
1778

1779
  push(op) {
1780
    assert(Opcode.isOpcode(op));
112✔
1781
    this.code.push(op);
112✔
1782
    return this;
112✔
1783
  }
1784

1785
  unshift(op) {
1786
    assert(Opcode.isOpcode(op));
×
1787
    this.code.unshift(op);
×
1788
    return this;
×
1789
  }
1790

1791
  insert(index, op) {
1792
    if (index < 0)
×
1793
      index += this.code.length;
×
1794

1795
    assert(Opcode.isOpcode(op));
×
1796
    assert(index >= 0 && index <= this.code.length);
×
1797

1798
    this.code.splice(index, 0, op);
×
1799

1800
    return this;
×
1801
  }
1802

1803
  /*
1804
   * Op
1805
   */
1806

1807
  getOp(index) {
UNCOV
1808
    const op = this.get(index);
×
UNCOV
1809
    return op ? op.value : -1;
×
1810
  }
1811

1812
  popOp() {
1813
    const op = this.pop();
×
1814
    return op ? op.value : -1;
×
1815
  }
1816

1817
  shiftOp() {
1818
    const op = this.shift();
×
1819
    return op ? op.value : -1;
×
1820
  }
1821

1822
  removeOp(index) {
1823
    const op = this.remove(index);
×
1824
    return op ? op.value : -1;
×
1825
  }
1826

1827
  setOp(index, value) {
1828
    return this.set(index, Opcode.fromOp(value));
×
1829
  }
1830

1831
  pushOp(value) {
1832
    return this.push(Opcode.fromOp(value));
105✔
1833
  }
1834

1835
  unshiftOp(value) {
1836
    return this.unshift(Opcode.fromOp(value));
×
1837
  }
1838

1839
  insertOp(index, value) {
1840
    return this.insert(index, Opcode.fromOp(value));
×
1841
  }
1842

1843
  /*
1844
   * Data
1845
   */
1846

1847
  getData(index) {
UNCOV
1848
    const op = this.get(index);
×
UNCOV
1849
    return op ? op.data : null;
×
1850
  }
1851

1852
  popData() {
1853
    const op = this.pop();
×
1854
    return op ? op.data : null;
×
1855
  }
1856

1857
  shiftData() {
1858
    const op = this.shift();
×
1859
    return op ? op.data : null;
×
1860
  }
1861

1862
  removeData(index) {
1863
    const op = this.remove(index);
×
1864
    return op ? op.data : null;
×
1865
  }
1866

1867
  setData(index, data) {
1868
    return this.set(index, Opcode.fromData(data));
×
1869
  }
1870

1871
  pushData(data) {
UNCOV
1872
    return this.push(Opcode.fromData(data));
×
1873
  }
1874

1875
  unshiftData(data) {
1876
    return this.unshift(Opcode.fromData(data));
×
1877
  }
1878

1879
  insertData(index, data) {
1880
    return this.insert(index, Opcode.fromData(data));
×
1881
  }
1882

1883
  /*
1884
   * Length
1885
   */
1886

1887
  getLength(index) {
1888
    const op = this.get(index);
×
1889
    return op ? op.toLength() : -1;
×
1890
  }
1891

1892
  /*
1893
   * Push
1894
   */
1895

1896
  getPush(index) {
1897
    const op = this.get(index);
×
1898
    return op ? op.toPush() : null;
×
1899
  }
1900

1901
  popPush() {
1902
    const op = this.pop();
×
1903
    return op ? op.toPush() : null;
×
1904
  }
1905

1906
  shiftPush() {
1907
    const op = this.shift();
×
1908
    return op ? op.toPush() : null;
×
1909
  }
1910

1911
  removePush(index) {
1912
    const op = this.remove(index);
×
1913
    return op ? op.toPush() : null;
×
1914
  }
1915

1916
  setPush(index, data) {
1917
    return this.set(index, Opcode.fromPush(data));
×
1918
  }
1919

1920
  pushPush(data) {
1921
    return this.push(Opcode.fromPush(data));
×
1922
  }
1923

1924
  unshiftPush(data) {
1925
    return this.unshift(Opcode.fromPush(data));
×
1926
  }
1927

1928
  insertPush(index, data) {
1929
    return this.insert(index, Opcode.fromPush(data));
×
1930
  }
1931

1932
  /*
1933
   * String
1934
   */
1935

1936
  getString(index, enc) {
1937
    const op = this.get(index);
×
1938
    return op ? op.toString(enc) : null;
×
1939
  }
1940

1941
  popString(enc) {
1942
    const op = this.pop();
×
1943
    return op ? op.toString(enc) : null;
×
1944
  }
1945

1946
  shiftString(enc) {
1947
    const op = this.shift();
×
1948
    return op ? op.toString(enc) : null;
×
1949
  }
1950

1951
  removeString(index, enc) {
1952
    const op = this.remove(index);
×
1953
    return op ? op.toString(enc) : null;
×
1954
  }
1955

1956
  setString(index, str, enc) {
1957
    return this.set(index, Opcode.fromString(str, enc));
×
1958
  }
1959

1960
  pushString(str, enc) {
1961
    return this.push(Opcode.fromString(str, enc));
×
1962
  }
1963

1964
  unshiftString(str, enc) {
1965
    return this.unshift(Opcode.fromString(str, enc));
×
1966
  }
1967

1968
  insertString(index, str, enc) {
1969
    return this.insert(index, Opcode.fromString(str, enc));
×
1970
  }
1971

1972
  /*
1973
   * Small
1974
   */
1975

1976
  getSmall(index) {
UNCOV
1977
    const op = this.get(index);
×
UNCOV
1978
    return op ? op.toSmall() : -1;
×
1979
  }
1980

1981
  popSmall() {
1982
    const op = this.pop();
×
1983
    return op ? op.toSmall() : -1;
×
1984
  }
1985

1986
  shiftSmall() {
1987
    const op = this.shift();
×
1988
    return op ? op.toSmall() : -1;
×
1989
  }
1990

1991
  removeSmall(index) {
1992
    const op = this.remove(index);
×
1993
    return op ? op.toSmall() : -1;
×
1994
  }
1995

1996
  setSmall(index, num) {
1997
    return this.set(index, Opcode.fromSmall(num));
×
1998
  }
1999

2000
  pushSmall(num) {
UNCOV
2001
    return this.push(Opcode.fromSmall(num));
×
2002
  }
2003

2004
  unshiftSmall(num) {
2005
    return this.unshift(Opcode.fromSmall(num));
×
2006
  }
2007

2008
  insertSmall(index, num) {
2009
    return this.insert(index, Opcode.fromSmall(num));
×
2010
  }
2011

2012
  /*
2013
   * Num
2014
   */
2015

2016
  getNum(index, minimal, limit) {
2017
    const op = this.get(index);
×
2018
    return op ? op.toNum(minimal, limit) : null;
×
2019
  }
2020

2021
  popNum(minimal, limit) {
2022
    const op = this.pop();
×
2023
    return op ? op.toNum(minimal, limit) : null;
×
2024
  }
2025

2026
  shiftNum(minimal, limit) {
2027
    const op = this.shift();
×
2028
    return op ? op.toNum(minimal, limit) : null;
×
2029
  }
2030

2031
  removeNum(index, minimal, limit) {
2032
    const op = this.remove(index);
×
2033
    return op ? op.toNum(minimal, limit) : null;
×
2034
  }
2035

2036
  setNum(index, num) {
2037
    return this.set(index, Opcode.fromNum(num));
×
2038
  }
2039

2040
  pushNum(num) {
2041
    return this.push(Opcode.fromNum(num));
×
2042
  }
2043

2044
  unshiftNum(num) {
2045
    return this.unshift(Opcode.fromNum(num));
×
2046
  }
2047

2048
  insertNum(index, num) {
2049
    return this.insert(index, Opcode.fromNum(num));
×
2050
  }
2051

2052
  /*
2053
   * Int
2054
   */
2055

2056
  getInt(index, minimal, limit) {
2057
    const op = this.get(index);
×
2058
    return op ? op.toInt(minimal, limit) : -1;
×
2059
  }
2060

2061
  popInt(minimal, limit) {
2062
    const op = this.pop();
×
2063
    return op ? op.toInt(minimal, limit) : -1;
×
2064
  }
2065

2066
  shiftInt(minimal, limit) {
2067
    const op = this.shift();
×
2068
    return op ? op.toInt(minimal, limit) : -1;
×
2069
  }
2070

2071
  removeInt(index, minimal, limit) {
2072
    const op = this.remove(index);
×
2073
    return op ? op.toInt(minimal, limit) : -1;
×
2074
  }
2075

2076
  setInt(index, num) {
2077
    return this.set(index, Opcode.fromInt(num));
×
2078
  }
2079

2080
  pushInt(num) {
2081
    return this.push(Opcode.fromInt(num));
×
2082
  }
2083

2084
  unshiftInt(num) {
2085
    return this.unshift(Opcode.fromInt(num));
×
2086
  }
2087

2088
  insertInt(index, num) {
2089
    return this.insert(index, Opcode.fromInt(num));
×
2090
  }
2091

2092
  /*
2093
   * Bool
2094
   */
2095

2096
  getBool(index) {
2097
    const op = this.get(index);
×
2098
    return op ? op.toBool() : false;
×
2099
  }
2100

2101
  popBool() {
2102
    const op = this.pop();
×
2103
    return op ? op.toBool() : false;
×
2104
  }
2105

2106
  shiftBool() {
2107
    const op = this.shift();
×
2108
    return op ? op.toBool() : false;
×
2109
  }
2110

2111
  removeBool(index) {
2112
    const op = this.remove(index);
×
2113
    return op ? op.toBool() : false;
×
2114
  }
2115

2116
  setBool(index, value) {
2117
    return this.set(index, Opcode.fromBool(value));
×
2118
  }
2119

2120
  pushBool(value) {
2121
    return this.push(Opcode.fromBool(value));
×
2122
  }
2123

2124
  unshiftBool(value) {
2125
    return this.unshift(Opcode.fromBool(value));
×
2126
  }
2127

2128
  insertBool(index, value) {
2129
    return this.insert(index, Opcode.fromBool(value));
×
2130
  }
2131

2132
  /*
2133
   * Symbol
2134
   */
2135

2136
  getSym(index) {
2137
    const op = this.get(index);
×
2138
    return op ? op.toSymbol() : null;
×
2139
  }
2140

2141
  popSym() {
2142
    const op = this.pop();
×
2143
    return op ? op.toSymbol() : null;
×
2144
  }
2145

2146
  shiftSym() {
2147
    const op = this.shift();
×
2148
    return op ? op.toSymbol() : null;
×
2149
  }
2150

2151
  removeSym(index) {
2152
    const op = this.remove(index);
×
2153
    return op ? op.toSymbol() : null;
×
2154
  }
2155

2156
  setSym(index, symbol) {
2157
    return this.set(index, Opcode.fromSymbol(symbol));
×
2158
  }
2159

2160
  pushSym(symbol) {
2161
    return this.push(Opcode.fromSymbol(symbol));
×
2162
  }
2163

2164
  unshiftSym(symbol) {
2165
    return this.unshift(Opcode.fromSymbol(symbol));
×
2166
  }
2167

2168
  insertSym(index, symbol) {
2169
    return this.insert(index, Opcode.fromSymbol(symbol));
×
2170
  }
2171

2172
  /**
2173
   * Inject properties from bitcoind test string.
2174
   * @private
2175
   * @param {String} items - Script string.
2176
   * @throws Parse error.
2177
   */
2178

2179
  fromString(code) {
2180
    assert(typeof code === 'string');
876✔
2181

2182
    code = code.trim();
876✔
2183

2184
    if (code.length === 0)
876✔
2185
      return this;
4✔
2186

2187
    const items = code.split(/\s+/);
872✔
2188
    const bw = bio.write();
872✔
2189

2190
    for (const item of items) {
872✔
2191
      let symbol = item;
8,282✔
2192

2193
      if (symbol.charCodeAt(0) & 32)
8,282✔
2194
        symbol = symbol.toUpperCase();
1,690✔
2195

2196
      if (!/^OP_/.test(symbol))
8,282✔
2197
        symbol = `OP_${symbol}`;
1,690✔
2198

2199
      const value = opcodes[symbol];
8,282✔
2200

2201
      if (value == null) {
8,282✔
2202
        if (item[0] === '\'') {
1,690!
2203
          assert(item[item.length - 1] === '\'', 'Invalid string.');
×
2204
          const str = item.slice(1, -1);
×
2205
          const op = Opcode.fromString(str);
×
2206
          bw.writeBytes(op.encode());
×
2207
          continue;
×
2208
        }
2209

2210
        if (/^-?\d+$/.test(item)) {
1,690✔
2211
          const num = ScriptNum.fromString(item, 10);
1,253✔
2212
          const op = Opcode.fromNum(num);
1,253✔
2213
          bw.writeBytes(op.encode());
1,253✔
2214
          continue;
1,253✔
2215
        }
2216

2217
        assert(item.indexOf('0x') === 0, 'Unknown opcode.');
437✔
2218

2219
        const hex = item.substring(2);
437✔
2220
        const data = Buffer.from(hex, 'hex');
437✔
2221

2222
        assert(data.length === hex.length / 2, 'Invalid hex string.');
437✔
2223

2224
        bw.writeBytes(data);
437✔
2225

2226
        continue;
437✔
2227
      }
2228

2229
      bw.writeU8(value);
6,592✔
2230
    }
2231

2232
    return this.decode(bw.render());
872✔
2233
  }
2234

2235
  /**
2236
   * Verify an input and output script, and a witness if present.
2237
   * @param {Witness} witness
2238
   * @param {Address} addr
2239
   * @param {TX} tx
2240
   * @param {Number} index
2241
   * @param {Amount} value
2242
   * @param {VerifyFlags} flags
2243
   * @throws {ScriptError}
2244
   */
2245

2246
  static verify(witness, addr, tx, index, value, flags) {
UNCOV
2247
    if (flags == null)
×
UNCOV
2248
      flags = Script.flags.STANDARD_VERIFY_FLAGS;
×
2249

UNCOV
2250
    assert(addr.version <= 31);
×
2251

UNCOV
2252
    if (addr.version === 31)
×
2253
      throw new ScriptError('OP_RETURN');
×
2254

UNCOV
2255
    if (witness.items.length > consensus.MAX_SCRIPT_STACK)
×
2256
      throw new ScriptError('STACK_SIZE');
×
2257

UNCOV
2258
    const stack = witness.toStack();
×
2259

UNCOV
2260
    let redeem = null;
×
2261

UNCOV
2262
    if (addr.version === 0) {
×
UNCOV
2263
      if (addr.hash.length === 32) {
×
UNCOV
2264
        if (stack.length === 0)
×
2265
          throw new ScriptError('WITNESS_PROGRAM_WITNESS_EMPTY');
×
2266

UNCOV
2267
        const witnessScript = stack.pop();
×
2268

UNCOV
2269
        if (witnessScript.length > consensus.MAX_SCRIPT_SIZE)
×
2270
          throw new ScriptError('SCRIPT_SIZE');
×
2271

UNCOV
2272
        if (!sha3.digest(witnessScript).equals(addr.hash))
×
UNCOV
2273
          throw new ScriptError('WITNESS_PROGRAM_MISMATCH');
×
2274

UNCOV
2275
        redeem = Script.decode(witnessScript);
×
UNCOV
2276
      } else if (addr.hash.length === 20) {
×
UNCOV
2277
        if (stack.length !== 2)
×
UNCOV
2278
          throw new ScriptError('WITNESS_PROGRAM_MISMATCH');
×
2279

UNCOV
2280
        redeem = Script.fromPubkeyhash(addr.hash);
×
2281
      } else {
2282
        // Failure on version=0 (bad program data length).
2283
        throw new ScriptError('WITNESS_PROGRAM_WRONG_LENGTH');
×
2284
      }
2285
    } else {
2286
      if (flags & Script.flags.VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM)
×
2287
        throw new ScriptError('DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM');
×
2288
      return;
×
2289
    }
2290

2291
    // Witnesses still have push limits.
UNCOV
2292
    for (let j = 0; j < stack.length; j++) {
×
UNCOV
2293
      if (stack.get(j).length > consensus.MAX_SCRIPT_PUSH)
×
2294
        throw new ScriptError('PUSH_SIZE');
×
2295
    }
2296

2297
    // Verify the redeem script.
UNCOV
2298
    redeem.execute(stack, flags, tx, index, value);
×
2299

2300
    // Verify the stack values.
UNCOV
2301
    if (stack.length !== 1 || !stack.getBool(-1))
×
UNCOV
2302
      throw new ScriptError('EVAL_FALSE');
×
2303
  }
2304

2305
  /**
2306
   * Inject properties from buffer reader.
2307
   * @private
2308
   * @param {BufferReader} br
2309
   */
2310

2311
  read(br) {
2312
    return this.decode(br.readVarBytes());
×
2313
  }
2314

2315
  /**
2316
   * Inject properties from serialized data.
2317
   * @private
2318
   * @param {Buffer}
2319
   */
2320

2321
  decode(data) {
2322
    const br = bio.read(data);
872✔
2323

2324
    this.raw = data;
872✔
2325

2326
    while (br.left())
872✔
2327
      this.code.push(Opcode.read(br));
8,122✔
2328

2329
    return this;
872✔
2330
  }
2331

2332
  /**
2333
   * Test whether an object a Script.
2334
   * @param {Object} obj
2335
   * @returns {Boolean}
2336
   */
2337

2338
  static isScript(obj) {
2339
    return obj instanceof Script;
×
2340
  }
2341
}
2342

2343
/**
2344
 * Script opcodes.
2345
 * @enum {Number}
2346
 * @default
2347
 */
2348

2349
Script.opcodes = common.opcodes;
1✔
2350

2351
/**
2352
 * Opcodes by value.
2353
 * @const {RevMap}
2354
 */
2355

2356
Script.opcodesByVal = common.opcodesByVal;
1✔
2357

2358
/**
2359
 * Script and locktime flags. See {@link VerifyFlags}.
2360
 * @enum {Number}
2361
 */
2362

2363
Script.flags = common.flags;
1✔
2364

2365
/**
2366
 * Sighash Types.
2367
 * @enum {SighashType}
2368
 * @default
2369
 */
2370

2371
Script.hashType = common.hashType;
1✔
2372

2373
/**
2374
 * Sighash types by value.
2375
 * @const {RevMap}
2376
 */
2377

2378
Script.hashTypeByVal = common.hashTypeByVal;
1✔
2379

2380
/**
2381
 * Output script types.
2382
 * @enum {Number}
2383
 */
2384

2385
Script.types = common.types;
1✔
2386

2387
/**
2388
 * Output script types by value.
2389
 * @const {RevMap}
2390
 */
2391

2392
Script.typesByVal = common.typesByVal;
1✔
2393

2394
/*
2395
 * Helpers
2396
 */
2397

2398
function sortKeys(keys) {
UNCOV
2399
  return keys.slice().sort((a, b) => {
×
UNCOV
2400
    return a.compare(b);
×
2401
  });
2402
}
2403

2404
/**
2405
 * Test whether the data element is a valid key if VERIFY_STRICTENC is enabled.
2406
 * @param {Buffer} key
2407
 * @param {VerifyFlags?} flags
2408
 * @returns {Boolean}
2409
 * @throws {ScriptError}
2410
 */
2411

2412
function validateKey(key, flags) {
UNCOV
2413
  assert(Buffer.isBuffer(key));
×
UNCOV
2414
  assert(typeof flags === 'number');
×
2415

UNCOV
2416
  if (!common.isKeyEncoding(key))
×
UNCOV
2417
    throw new ScriptError('PUBKEY_ENCODING');
×
2418

UNCOV
2419
  return true;
×
2420
}
2421

2422
/**
2423
 * Test whether the data element is a valid signature based
2424
 * on the encoding, S value, and sighash type. Requires
2425
 * VERIFY_DERSIG|VERIFY_LOW_S|VERIFY_STRICTENC, VERIFY_LOW_S
2426
 * and VERIFY_STRING_ENC to be enabled respectively. Note that
2427
 * this will allow zero-length signatures.
2428
 * @param {Buffer} sig
2429
 * @param {VerifyFlags?} flags
2430
 * @returns {Boolean}
2431
 * @throws {ScriptError}
2432
 */
2433

2434
function validateSignature(sig, flags) {
UNCOV
2435
  assert(Buffer.isBuffer(sig));
×
UNCOV
2436
  assert(typeof flags === 'number');
×
2437

2438
  // Allow empty sigs
UNCOV
2439
  if (sig.length === 0)
×
UNCOV
2440
    return true;
×
2441

UNCOV
2442
  if (!common.isSignatureEncoding(sig))
×
UNCOV
2443
    throw new ScriptError('SIG_ENCODING');
×
2444

UNCOV
2445
  return true;
×
2446
}
2447

2448
/**
2449
 * Verify a signature, taking into account sighash type.
2450
 * @param {Buffer} msg - Signature hash.
2451
 * @param {Buffer} sig
2452
 * @param {Buffer} key
2453
 * @returns {Boolean}
2454
 */
2455

2456
function checksig(msg, sig, key) {
UNCOV
2457
  return secp256k1.verify(msg, sig.slice(0, -1), key);
×
2458
}
2459

2460
/*
2461
 * Expose
2462
 */
2463

2464
module.exports = Script;
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc