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

handshake-org / hsd / 15042451478

15 May 2025 10:16AM UTC coverage: 19.792% (-51.5%) from 71.269%
15042451478

Pull #928

github

web-flow
Merge fa1d30da4 into 5f11d622b
Pull Request #928: Wallet coinselection

1570 of 13236 branches covered (11.86%)

Branch coverage included in aggregate %.

217 of 388 new or added lines in 6 files covered. (55.93%)

17866 existing lines in 127 files now uncovered.

7855 of 34384 relevant lines covered (22.84%)

129.11 hits per line

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

10.18
/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
/** @typedef {import('@handshake-org/bfilter').BloomFilter} BloomFilter */
31
/** @typedef {import('../types').BufioWriter} BufioWriter */
32
/** @typedef {import('../types').SighashType} SighashType */
33
/** @typedef {import('../types').VerifyFlags} VerifyFlags */
34
/** @typedef {import('../types').Amount} AmountValue */
35
/** @typedef {import('../types').Hash} Hash */
36
/** @typedef {import('./witness')} Witness */
37
/** @typedef {import('../primitives/address')} Address */
38
/** @typedef {import('../primitives/tx')} TX */
39

40
/*
41
 * Constants
42
 */
43

44
const EMPTY_BUFFER = Buffer.alloc(0);
1✔
45

46
/**
47
 * Script
48
 * Represents a input or output script.
49
 * @alias module:script.Script
50
 * @property {Array} code - Parsed script code.
51
 * @property {Buffer?} raw - Serialized script.
52
 * @property {Number} length - Number of parsed opcodes.
53
 */
54

55
class Script extends bio.Struct {
56
  /**
57
   * Create a script.
58
   * @constructor
59
   * @param {Object?} [options]
60
   */
61

62
  constructor(options) {
63
    super();
914✔
64

65
    this.raw = EMPTY_BUFFER;
914✔
66
    /** @type {Opcode[]} */
67
    this.code = [];
914✔
68

69
    if (options)
914✔
70
      this.fromOptions(options);
3✔
71
  }
72

73
  /**
74
   * Get length.
75
   * @returns {Number}
76
   */
77

78
  get length() {
79
    return this.code.length;
×
80
  }
81

82
  /**
83
   * Set length.
84
   * @param {Number} value
85
   */
86

87
  set length(value) {
88
    this.code.length = value;
×
89
  }
90

91
  /**
92
   * Inject properties from options object.
93
   * @param {Object} options
94
   * @returns {this}
95
   */
96

97
  fromOptions(options) {
98
    assert(options, 'Script data is required.');
3✔
99

100
    if (Buffer.isBuffer(options))
3!
101
      return this.decode(options);
×
102

103
    if (Array.isArray(options))
3!
104
      return this.fromArray(options);
3✔
105

106
    if (options.raw) {
×
107
      if (!options.code)
×
108
        return this.decode(options.raw);
×
109
      assert(Buffer.isBuffer(options.raw), 'Raw must be a Buffer.');
×
110
      this.raw = options.raw;
×
111
    }
112

113
    if (options.code) {
×
114
      if (!options.raw)
×
115
        return this.fromArray(options.code);
×
116
      assert(Array.isArray(options.code), 'Code must be an array.');
×
117
      this.code = options.code;
×
118
    }
119

120
    return this;
×
121
  }
122

123
  /**
124
   * Instantiate a value-only iterator.
125
   */
126

127
  values() {
128
    return this.code.values();
×
129
  }
130

131
  /**
132
   * Instantiate a key and value iterator.
133
   */
134

135
  entries() {
136
    return this.code.entries();
×
137
  }
138

139
  /**
140
   * Instantiate a value-only iterator.
141
   */
142

143
  [Symbol.iterator]() {
144
    return this.code[Symbol.iterator]();
×
145
  }
146

147
  /**
148
   * Convert the script to an array of
149
   * Buffers (pushdatas) and Numbers
150
   * (opcodes).
151
   * @returns {Array}
152
   */
153

154
  toArray() {
155
    return this.code.slice();
×
156
  }
157

158
  /**
159
   * Inject properties from an array of
160
   * of buffers and numbers.
161
   * @param {Opcode[]} code
162
   * @returns {this}
163
   */
164

165
  fromArray(code) {
166
    assert(Array.isArray(code));
3✔
167

168
    this.clear();
3✔
169

170
    for (const op of code)
3✔
171
      this.push(op);
7✔
172

173
    return this.compile();
3✔
174
  }
175

176
  /**
177
   * Instantiate script from an array
178
   * of buffers and numbers.
179
   * @param {Opcode[]} code
180
   * @returns {Script}
181
   */
182

183
  static fromArray(code) {
184
    return new this().fromArray(code);
×
185
  }
186

187
  /**
188
   * Convert script to stack items.
189
   * @returns {Buffer[]}
190
   */
191

192
  toItems() {
193
    const items = [];
×
194

195
    for (const op of this.code) {
×
196
      const data = op.toPush();
×
197

198
      if (!data)
×
199
        throw new Error('Non-push opcode in script.');
×
200

201
      items.push(data);
×
202
    }
203

204
    return items;
×
205
  }
206

207
  /**
208
   * Inject data from stack items.
209
   * @param {Buffer[]} items
210
   * @returns {this}
211
   */
212

213
  fromItems(items) {
214
    assert(Array.isArray(items));
×
215

216
    this.clear();
×
217

218
    for (const item of items)
×
219
      this.pushData(item);
×
220

221
    return this.compile();
×
222
  }
223

224
  /**
225
   * Instantiate script from stack items.
226
   * @param {Buffer[]} items
227
   * @returns {Script}
228
   */
229

230
  static fromItems(items) {
231
    return new this().fromItems(items);
×
232
  }
233

234
  /**
235
   * Convert script to stack.
236
   * @returns {Stack}
237
   */
238

239
  toStack() {
240
    return new Stack(this.toItems());
×
241
  }
242

243
  /**
244
   * Inject data from stack.
245
   * @param {Stack} stack
246
   * @returns {this}
247
   */
248

249
  fromStack(stack) {
250
    return this.fromItems(stack.items);
×
251
  }
252

253
  /**
254
   * Instantiate script from stack.
255
   * @param {Stack} stack
256
   * @returns {Script}
257
   */
258

259
  static fromStack(stack) {
260
    return new this().fromStack(stack);
×
261
  }
262

263
  /**
264
   * Inject properties from script.
265
   * Used for cloning.
266
   * @param {this} script
267
   * @returns {this}
268
   */
269

270
  inject(script) {
UNCOV
271
    this.raw = script.raw;
×
UNCOV
272
    this.code = script.code.slice();
×
UNCOV
273
    return this;
×
274
  }
275

276
  /**
277
   * Test equality against script.
278
   * @param {Script} script
279
   * @returns {Boolean}
280
   */
281

282
  equals(script) {
283
    assert(Script.isScript(script));
×
284
    return this.raw.equals(script.raw);
×
285
  }
286

287
  /**
288
   * Compare against another script.
289
   * @param {Script} script
290
   * @returns {Number}
291
   */
292

293
  compare(script) {
294
    assert(Script.isScript(script));
×
295
    return this.raw.compare(script.raw);
×
296
  }
297

298
  /**
299
   * Clear the script.
300
   * @returns {this}
301
   */
302

303
  clear() {
304
    this.raw = EMPTY_BUFFER;
3✔
305
    this.code.length = 0;
3✔
306
    return this;
3✔
307
  }
308

309
  /**
310
   * Inspect the script.
311
   * @returns {String} Human-readable script code.
312
   */
313

314
  format() {
315
    return `<Script: ${this.toString()}>`;
×
316
  }
317

318
  /**
319
   * Convert the script to a bitcoind test string.
320
   * @returns {String} Human-readable script code.
321
   */
322

323
  toString() {
324
    const out = [];
×
325

326
    for (const op of this.code)
×
327
      out.push(op.toFormat());
×
328

329
    return out.join(' ');
×
330
  }
331

332
  /**
333
   * Format the script as bitcoind asm.
334
   * @param {Boolean?} decode - Attempt to decode hash types.
335
   * @returns {String} Human-readable script.
336
   */
337

338
  toASM(decode) {
339
    const out = [];
×
340

341
    for (const op of this.code)
×
342
      out.push(op.toASM(decode));
×
343

344
    return out.join(' ');
×
345
  }
346

347
  /**
348
   * Re-encode the script internally. Useful if you
349
   * changed something manually in the `code` array.
350
   */
351

352
  compile() {
353
    if (this.code.length === 0)
4!
354
      return this.clear();
×
355

356
    let size = 0;
4✔
357

358
    for (const op of this.code)
4✔
359
      size += op.getSize();
112✔
360

361
    const bw = bio.write(size);
4✔
362

363
    for (const op of this.code)
4✔
364
      op.write(bw);
112✔
365

366
    this.raw = bw.render();
4✔
367

368
    return this;
4✔
369
  }
370

371
  /**
372
   * Write the script to a buffer writer.
373
   * @param {BufioWriter} bw
374
   * @returns {BufioWriter}
375
   */
376

377
  write(bw) {
378
    bw.writeVarBytes(this.raw);
×
379
    return bw;
×
380
  }
381

382
  /**
383
   * Encode the script to a Buffer. See {@link Script#encode}.
384
   * @returns {Buffer} Serialized script.
385
   */
386

387
  encode() {
388
    return this.raw;
1,773✔
389
  }
390

391
  /**
392
   * Convert script to a hex string.
393
   * @returns {String}
394
   */
395

396
  getJSON() {
397
    return this.toHex();
×
398
  }
399

400
  /**
401
   * Inject properties from json object.
402
   * @param {String} json
403
   */
404

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

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

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

420
    /** @type {this} */
421
    const script = new Script();
×
422

423
    for (let i = index; i < this.code.length; i++) {
×
424
      const op = this.code[i];
×
425

426
      if (op.value === -1)
×
427
        break;
×
428

429
      script.code.push(op);
×
430
    }
431

432
    return script.compile();
×
433
  }
434

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

443
  removeSeparators() {
444
    let found = false;
×
445

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

452
      if (op.value === opcodes.OP_CODESEPARATOR) {
×
453
        found = true;
×
454
        break;
×
455
      }
456
    }
457

458
    if (!found)
×
459
      return this;
×
460

461
    // Uncommon case: someone actually
462
    // has a code separator. Go through
463
    // and remove them all.
464
    /** @type {this} */
465
    const script = new Script();
×
466

467
    for (const op of this.code) {
×
468
      if (op.value === -1)
×
469
        break;
×
470

471
      if (op.value !== opcodes.OP_CODESEPARATOR)
×
472
        script.code.push(op);
×
473
    }
474

475
    return script.compile();
×
476
  }
477

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

488
  execute(stack, flags, tx, index, value) {
UNCOV
489
    if (flags == null)
×
UNCOV
490
      flags = Script.flags.STANDARD_VERIFY_FLAGS;
×
491

UNCOV
492
    if (this.raw.length > consensus.MAX_SCRIPT_SIZE)
×
493
      throw new ScriptError('SCRIPT_SIZE');
×
494

UNCOV
495
    const state = [];
×
UNCOV
496
    const alt = [];
×
497

UNCOV
498
    let lastSep = 0;
×
UNCOV
499
    let opCount = 0;
×
UNCOV
500
    let negate = 0;
×
UNCOV
501
    let minimal = false;
×
502

UNCOV
503
    if (flags & Script.flags.VERIFY_MINIMALDATA)
×
UNCOV
504
      minimal = true;
×
505

UNCOV
506
    for (let ip = 0; ip < this.code.length; ip++) {
×
UNCOV
507
      const op = this.code[ip];
×
508

UNCOV
509
      if (op.value === -1)
×
510
        throw new ScriptError('BAD_OPCODE', op, ip);
×
511

UNCOV
512
      if (op.data && op.data.length > consensus.MAX_SCRIPT_PUSH)
×
UNCOV
513
        throw new ScriptError('PUSH_SIZE', op, ip);
×
514

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

UNCOV
518
      if (op.isDisabled())
×
UNCOV
519
        throw new ScriptError('DISABLED_OPCODE', op, ip);
×
520

UNCOV
521
      if (negate && !op.isBranch()) {
×
UNCOV
522
        if (stack.length + alt.length > consensus.MAX_SCRIPT_STACK)
×
523
          throw new ScriptError('STACK_SIZE', op, ip);
×
UNCOV
524
        continue;
×
525
      }
526

UNCOV
527
      if (op.data) {
×
UNCOV
528
        if (minimal && !op.isMinimal())
×
529
          throw new ScriptError('MINIMALDATA', op, ip);
×
530

UNCOV
531
        stack.push(op.data);
×
532

UNCOV
533
        if (stack.length + alt.length > consensus.MAX_SCRIPT_STACK)
×
534
          throw new ScriptError('STACK_SIZE', op, ip);
×
535

UNCOV
536
        continue;
×
537
      }
538

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

UNCOV
574
          if (index >= tx.outputs.length) {
×
575
            stack.pushInt(0);
×
576
            break;
×
577
          }
578

UNCOV
579
          const {covenant} = tx.outputs[index];
×
580

UNCOV
581
          stack.pushInt(covenant.type);
×
582

UNCOV
583
          break;
×
584
        }
585
        case opcodes.OP_CHECKLOCKTIMEVERIFY: {
UNCOV
586
          if (!tx)
×
587
            throw new ScriptError('UNKNOWN_ERROR', 'No TX passed in.');
×
588

UNCOV
589
          if (stack.length === 0)
×
590
            throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
×
591

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

UNCOV
594
          if (num.isNeg())
×
UNCOV
595
            throw new ScriptError('NEGATIVE_LOCKTIME', op, ip);
×
596

UNCOV
597
          const locktime = num.toDouble();
×
598

UNCOV
599
          if (!tx.verifyLocktime(index, locktime))
×
UNCOV
600
            throw new ScriptError('UNSATISFIED_LOCKTIME', op, ip);
×
601

602
          break;
×
603
        }
604
        case opcodes.OP_CHECKSEQUENCEVERIFY: {
UNCOV
605
          if (!tx)
×
606
            throw new ScriptError('UNKNOWN_ERROR', 'No TX passed in.');
×
607

UNCOV
608
          if (stack.length === 0)
×
UNCOV
609
            throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
×
610

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

UNCOV
613
          if (num.isNeg())
×
UNCOV
614
            throw new ScriptError('NEGATIVE_LOCKTIME', op, ip);
×
615

UNCOV
616
          const locktime = num.toDouble();
×
617

UNCOV
618
          if (!tx.verifySequence(index, locktime))
×
UNCOV
619
            throw new ScriptError('UNSATISFIED_LOCKTIME', op, ip);
×
620

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

UNCOV
639
          if (!negate) {
×
UNCOV
640
            if (stack.length < 1)
×
641
              throw new ScriptError('UNBALANCED_CONDITIONAL', op, ip);
×
642

UNCOV
643
            if (flags & Script.flags.VERIFY_MINIMALIF) {
×
UNCOV
644
              const item = stack.get(-1);
×
645

UNCOV
646
              if (item.length > 1)
×
UNCOV
647
                throw new ScriptError('MINIMALIF');
×
648

UNCOV
649
              if (item.length === 1 && item[0] !== 1)
×
UNCOV
650
                throw new ScriptError('MINIMALIF');
×
651
            }
652

UNCOV
653
            val = stack.getBool(-1);
×
654

UNCOV
655
            if (op.value === opcodes.OP_NOTIF)
×
UNCOV
656
              val = !val;
×
657

UNCOV
658
            stack.pop();
×
659
          }
660

UNCOV
661
          state.push(val);
×
662

UNCOV
663
          if (!val)
×
UNCOV
664
            negate += 1;
×
665

UNCOV
666
          break;
×
667
        }
668
        case opcodes.OP_ELSE: {
UNCOV
669
          if (state.length === 0)
×
UNCOV
670
            throw new ScriptError('UNBALANCED_CONDITIONAL', op, ip);
×
671

UNCOV
672
          state[state.length - 1] = !state[state.length - 1];
×
673

UNCOV
674
          if (!state[state.length - 1])
×
UNCOV
675
            negate += 1;
×
676
          else
UNCOV
677
            negate -= 1;
×
678

UNCOV
679
          break;
×
680
        }
681
        case opcodes.OP_ENDIF: {
UNCOV
682
          if (state.length === 0)
×
UNCOV
683
            throw new ScriptError('UNBALANCED_CONDITIONAL', op, ip);
×
684

UNCOV
685
          if (!state.pop())
×
UNCOV
686
            negate -= 1;
×
687

UNCOV
688
          break;
×
689
        }
690
        case opcodes.OP_VERIFY: {
UNCOV
691
          if (stack.length === 0)
×
692
            throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
×
693

UNCOV
694
          if (!stack.getBool(-1))
×
UNCOV
695
            throw new ScriptError('VERIFY', op, ip);
×
696

UNCOV
697
          stack.pop();
×
698

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

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

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

UNCOV
722
          stack.pop();
×
UNCOV
723
          stack.pop();
×
UNCOV
724
          break;
×
725
        }
726
        case opcodes.OP_2DUP: {
UNCOV
727
          if (stack.length < 2)
×
UNCOV
728
            throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
×
729

UNCOV
730
          const v1 = stack.get(-2);
×
UNCOV
731
          const v2 = stack.get(-1);
×
732

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

UNCOV
741
          const v1 = stack.get(-3);
×
UNCOV
742
          const v2 = stack.get(-2);
×
UNCOV
743
          const v3 = stack.get(-1);
×
744

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

UNCOV
754
          const v1 = stack.get(-4);
×
UNCOV
755
          const v2 = stack.get(-3);
×
756

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

UNCOV
765
          const v1 = stack.get(-6);
×
UNCOV
766
          const v2 = stack.get(-5);
×
767

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

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

UNCOV
785
          if (stack.getBool(-1)) {
×
UNCOV
786
            const val = stack.get(-1);
×
UNCOV
787
            stack.push(val);
×
788
          }
789

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

UNCOV
800
          stack.pop();
×
UNCOV
801
          break;
×
802
        }
803
        case opcodes.OP_DUP: {
UNCOV
804
          if (stack.length === 0)
×
805
            throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
×
806

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

UNCOV
814
          stack.remove(-2);
×
UNCOV
815
          break;
×
816
        }
817
        case opcodes.OP_OVER: {
UNCOV
818
          if (stack.length < 2)
×
UNCOV
819
            throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
×
820

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

UNCOV
829
          const num = stack.getInt(-1, minimal, 4);
×
UNCOV
830
          stack.pop();
×
831

UNCOV
832
          if (num < 0 || num >= stack.length)
×
UNCOV
833
            throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
×
834

UNCOV
835
          const val = stack.get(-num - 1);
×
836

UNCOV
837
          if (op.value === opcodes.OP_ROLL)
×
UNCOV
838
            stack.remove(-num - 1);
×
839

UNCOV
840
          stack.push(val);
×
UNCOV
841
          break;
×
842
        }
843
        case opcodes.OP_ROT: {
UNCOV
844
          if (stack.length < 3)
×
UNCOV
845
            throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
×
846

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

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

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

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

UNCOV
877
          const v1 = stack.get(-2);
×
UNCOV
878
          const v2 = stack.get(-1);
×
879

UNCOV
880
          const res = v1.equals(v2);
×
881

UNCOV
882
          stack.pop();
×
UNCOV
883
          stack.pop();
×
884

UNCOV
885
          stack.pushBool(res);
×
886

UNCOV
887
          if (op.value === opcodes.OP_EQUALVERIFY) {
×
UNCOV
888
            if (!res)
×
UNCOV
889
              throw new ScriptError('EQUALVERIFY', op, ip);
×
UNCOV
890
            stack.pop();
×
891
          }
892

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

UNCOV
904
          let num = stack.getNum(-1, minimal, 4);
×
905
          let cmp;
906

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

UNCOV
933
          stack.pop();
×
UNCOV
934
          stack.pushNum(num);
×
935

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

UNCOV
954
          const n1 = stack.getNum(-2, minimal, 4);
×
UNCOV
955
          const n2 = stack.getNum(-1, minimal, 4);
×
956

957
          let num, cmp;
958

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

UNCOV
1013
          stack.pop();
×
UNCOV
1014
          stack.pop();
×
UNCOV
1015
          stack.pushNum(num);
×
1016

UNCOV
1017
          if (op.value === opcodes.OP_NUMEQUALVERIFY) {
×
UNCOV
1018
            if (!stack.getBool(-1))
×
1019
              throw new ScriptError('NUMEQUALVERIFY', op, ip);
×
UNCOV
1020
            stack.pop();
×
1021
          }
1022

UNCOV
1023
          break;
×
1024
        }
1025
        case opcodes.OP_WITHIN: {
UNCOV
1026
          if (stack.length < 3)
×
UNCOV
1027
            throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
×
1028

UNCOV
1029
          const n1 = stack.getNum(-3, minimal, 4);
×
UNCOV
1030
          const n2 = stack.getNum(-2, minimal, 4);
×
UNCOV
1031
          const n3 = stack.getNum(-1, minimal, 4);
×
1032

UNCOV
1033
          const val = n2.lte(n1) && n1.lt(n3);
×
1034

UNCOV
1035
          stack.pop();
×
UNCOV
1036
          stack.pop();
×
UNCOV
1037
          stack.pop();
×
1038

UNCOV
1039
          stack.pushBool(val);
×
UNCOV
1040
          break;
×
1041
        }
1042
        case opcodes.OP_RIPEMD160: {
UNCOV
1043
          if (stack.length === 0)
×
1044
            throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
×
1045

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

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

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

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

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

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

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

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

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

UNCOV
1114
          if (stack.length < 2)
×
UNCOV
1115
            throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
×
1116

UNCOV
1117
          const sig = stack.get(-2);
×
UNCOV
1118
          const key = stack.get(-1);
×
1119

UNCOV
1120
          const subscript = this.getSubscript(lastSep);
×
1121

UNCOV
1122
          validateSignature(sig, flags);
×
UNCOV
1123
          validateKey(key, flags);
×
1124

UNCOV
1125
          let res = false;
×
1126

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

UNCOV
1138
          if (!res && (flags & Script.flags.VERIFY_NULLFAIL)) {
×
UNCOV
1139
            if (sig.length !== 0)
×
UNCOV
1140
              throw new ScriptError('NULLFAIL', op, ip);
×
1141
          }
1142

UNCOV
1143
          stack.pop();
×
UNCOV
1144
          stack.pop();
×
1145

UNCOV
1146
          stack.pushBool(res);
×
1147

UNCOV
1148
          if (op.value === opcodes.OP_CHECKSIGVERIFY) {
×
1149
            if (!res)
×
1150
              throw new ScriptError('CHECKSIGVERIFY', op, ip);
×
1151
            stack.pop();
×
1152
          }
1153

UNCOV
1154
          break;
×
1155
        }
1156
        case opcodes.OP_CHECKMULTISIG:
1157
        case opcodes.OP_CHECKMULTISIGVERIFY: {
UNCOV
1158
          if (!tx)
×
1159
            throw new ScriptError('UNKNOWN_ERROR', 'No TX passed in.');
×
1160

UNCOV
1161
          let i = 1;
×
UNCOV
1162
          if (stack.length < i)
×
UNCOV
1163
            throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
×
1164

UNCOV
1165
          let n = stack.getInt(-i, minimal, 4);
×
UNCOV
1166
          let okey = n + 2;
×
1167
          let ikey, isig;
1168

UNCOV
1169
          if (n < 0 || n > consensus.MAX_MULTISIG_PUBKEYS)
×
UNCOV
1170
            throw new ScriptError('PUBKEY_COUNT', op, ip);
×
1171

UNCOV
1172
          opCount += n;
×
1173

UNCOV
1174
          if (opCount > consensus.MAX_SCRIPT_OPS)
×
UNCOV
1175
            throw new ScriptError('OP_COUNT', op, ip);
×
1176

UNCOV
1177
          i += 1;
×
UNCOV
1178
          ikey = i;
×
UNCOV
1179
          i += n;
×
1180

UNCOV
1181
          if (stack.length < i)
×
UNCOV
1182
            throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
×
1183

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

UNCOV
1186
          if (m < 0 || m > n)
×
UNCOV
1187
            throw new ScriptError('SIG_COUNT', op, ip);
×
1188

UNCOV
1189
          i += 1;
×
UNCOV
1190
          isig = i;
×
UNCOV
1191
          i += m;
×
1192

UNCOV
1193
          if (stack.length < i)
×
UNCOV
1194
            throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
×
1195

UNCOV
1196
          const subscript = this.getSubscript(lastSep);
×
1197

UNCOV
1198
          let res = true;
×
UNCOV
1199
          while (res && m > 0) {
×
UNCOV
1200
            const sig = stack.get(-isig);
×
UNCOV
1201
            const key = stack.get(-ikey);
×
1202

UNCOV
1203
            validateSignature(sig, flags);
×
UNCOV
1204
            validateKey(key, flags);
×
1205

UNCOV
1206
            if (sig.length > 0) {
×
UNCOV
1207
              const type = sig[sig.length - 1];
×
UNCOV
1208
              const hash = tx.signatureHash(
×
1209
                index,
1210
                subscript,
1211
                value,
1212
                type
1213
              );
1214

UNCOV
1215
              if (checksig(hash, sig, key)) {
×
UNCOV
1216
                isig += 1;
×
UNCOV
1217
                m -= 1;
×
1218
              }
1219
            }
1220

UNCOV
1221
            ikey += 1;
×
UNCOV
1222
            n -= 1;
×
1223

UNCOV
1224
            if (m > n)
×
UNCOV
1225
              res = false;
×
1226
          }
1227

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

UNCOV
1234
            if (okey > 0)
×
UNCOV
1235
              okey -= 1;
×
1236

UNCOV
1237
            stack.pop();
×
1238

UNCOV
1239
            i -= 1;
×
1240
          }
1241

UNCOV
1242
          if (stack.length < 1)
×
1243
            throw new ScriptError('INVALID_STACK_OPERATION', op, ip);
×
1244

UNCOV
1245
          if (stack.get(-1).length !== 0)
×
UNCOV
1246
            throw new ScriptError('SIG_NULLDUMMY', op, ip);
×
1247

UNCOV
1248
          stack.pop();
×
1249

UNCOV
1250
          stack.pushBool(res);
×
1251

UNCOV
1252
          if (op.value === opcodes.OP_CHECKMULTISIGVERIFY) {
×
UNCOV
1253
            if (!res)
×
1254
              throw new ScriptError('CHECKMULTISIGVERIFY', op, ip);
×
UNCOV
1255
            stack.pop();
×
1256
          }
1257

UNCOV
1258
          break;
×
1259
        }
1260
        default: {
UNCOV
1261
          throw new ScriptError('BAD_OPCODE', op, ip);
×
1262
        }
1263
      }
1264

UNCOV
1265
      if (stack.length + alt.length > consensus.MAX_SCRIPT_STACK)
×
1266
        throw new ScriptError('STACK_SIZE', op, ip);
×
1267
    }
1268

UNCOV
1269
    if (state.length !== 0)
×
UNCOV
1270
      throw new ScriptError('UNBALANCED_CONDITIONAL');
×
1271
  }
1272

1273
  /**
1274
   * Find a data element in a script.
1275
   * @param {Buffer} data - Data element to match against.
1276
   * @returns {Number} Index (`-1` if not present).
1277
   */
1278

1279
  indexOf(data) {
UNCOV
1280
    for (let i = 0; i < this.code.length; i++) {
×
UNCOV
1281
      const op = this.code[i];
×
1282

UNCOV
1283
      if (op.value === -1)
×
1284
        break;
×
1285

UNCOV
1286
      if (!op.data)
×
UNCOV
1287
        continue;
×
1288

UNCOV
1289
      if (op.data.equals(data))
×
UNCOV
1290
        return i;
×
1291
    }
1292

1293
    return -1;
×
1294
  }
1295

1296
  /**
1297
   * Test a script to see if it is likely
1298
   * to be script code (no weird opcodes).
1299
   * @returns {Boolean}
1300
   */
1301

1302
  isCode() {
1303
    for (const op of this.code) {
×
1304
      if (op.value === -1)
×
1305
        return false;
×
1306

1307
      if (op.isDisabled())
×
1308
        return false;
×
1309

1310
      switch (op.value) {
×
1311
        case opcodes.OP_RESERVED:
1312
        case opcodes.OP_NOP:
1313
        case opcodes.OP_VER:
1314
        case opcodes.OP_VERIF:
1315
        case opcodes.OP_VERNOTIF:
1316
        case opcodes.OP_RESERVED1:
1317
        case opcodes.OP_RESERVED2:
1318
          return false;
×
1319
      }
1320

1321
      if (op.value > opcodes.OP_CHECKSEQUENCEVERIFY)
×
1322
        return false;
×
1323
    }
1324

1325
    return true;
×
1326
  }
1327

1328
  /**
1329
   * Inject properties from a pay-to-pubkey script.
1330
   * @param {Buffer} key
1331
   * @returns {this}
1332
   */
1333

1334
  fromPubkey(key) {
1335
    assert(Buffer.isBuffer(key) && key.length === 33);
×
1336

1337
    this.raw = Buffer.allocUnsafe(35);
×
1338
    this.raw[0] = 33;
×
1339
    key.copy(this.raw, 1);
×
1340
    this.raw[34] = opcodes.OP_CHECKSIG;
×
1341

1342
    key = this.raw.slice(1, 34);
×
1343

1344
    this.code.length = 0;
×
1345
    this.code.push(Opcode.fromPush(key));
×
1346
    this.code.push(Opcode.fromOp(opcodes.OP_CHECKSIG));
×
1347

1348
    return this;
×
1349
  }
1350

1351
  /**
1352
   * Create a pay-to-pubkey script.
1353
   * @param {Buffer} key
1354
   * @returns {Script}
1355
   */
1356

1357
  static fromPubkey(key) {
1358
    return new this().fromPubkey(key);
×
1359
  }
1360

1361
  /**
1362
   * Inject properties from a pay-to-pubkeyhash script.
1363
   * @private
1364
   * @param {Buffer} hash
1365
   */
1366

1367
  fromPubkeyhash(hash) {
1368
    assert(Buffer.isBuffer(hash) && hash.length === 20);
33✔
1369

1370
    this.raw = Buffer.allocUnsafe(25);
33✔
1371
    this.raw[0] = opcodes.OP_DUP;
33✔
1372
    this.raw[1] = opcodes.OP_BLAKE160;
33✔
1373
    this.raw[2] = 0x14;
33✔
1374
    hash.copy(this.raw, 3);
33✔
1375
    this.raw[23] = opcodes.OP_EQUALVERIFY;
33✔
1376
    this.raw[24] = opcodes.OP_CHECKSIG;
33✔
1377

1378
    hash = this.raw.slice(3, 23);
33✔
1379

1380
    this.code.length = 0;
33✔
1381
    this.code.push(Opcode.fromOp(opcodes.OP_DUP));
33✔
1382
    this.code.push(Opcode.fromOp(opcodes.OP_BLAKE160));
33✔
1383
    this.code.push(Opcode.fromPush(hash));
33✔
1384
    this.code.push(Opcode.fromOp(opcodes.OP_EQUALVERIFY));
33✔
1385
    this.code.push(Opcode.fromOp(opcodes.OP_CHECKSIG));
33✔
1386

1387
    return this;
33✔
1388
  }
1389

1390
  /**
1391
   * Create a pay-to-pubkeyhash script.
1392
   * @param {Buffer} hash
1393
   * @returns {Script}
1394
   */
1395

1396
  static fromPubkeyhash(hash) {
1397
    return new this().fromPubkeyhash(hash);
33✔
1398
  }
1399

1400
  /**
1401
   * Inject properties from pay-to-multisig script.
1402
   * @private
1403
   * @param {Number} m
1404
   * @param {Number} n
1405
   * @param {Buffer[]} keys
1406
   */
1407

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

UNCOV
1415
    this.clear();
×
1416

UNCOV
1417
    this.pushSmall(m);
×
1418

UNCOV
1419
    for (const key of sortKeys(keys))
×
UNCOV
1420
      this.pushData(key);
×
1421

UNCOV
1422
    this.pushSmall(n);
×
UNCOV
1423
    this.pushOp(opcodes.OP_CHECKMULTISIG);
×
1424

UNCOV
1425
    return this.compile();
×
1426
  }
1427

1428
  /**
1429
   * Create a pay-to-multisig script.
1430
   * @param {Number} m
1431
   * @param {Number} n
1432
   * @param {Buffer[]} keys
1433
   * @returns {Script}
1434
   */
1435

1436
  static fromMultisig(m, n, keys) {
UNCOV
1437
    return new this().fromMultisig(m, n, keys);
×
1438
  }
1439

1440
  /**
1441
   * Get the standard script type.
1442
   * @returns {common.types}
1443
   */
1444

1445
  getType() {
1446
    if (this.isPubkey())
×
1447
      return scriptTypes.PUBKEY;
×
1448

1449
    if (this.isPubkeyhash())
×
1450
      return scriptTypes.PUBKEYHASH;
×
1451

1452
    if (this.isMultisig())
×
1453
      return scriptTypes.MULTISIG;
×
1454

1455
    return scriptTypes.NONSTANDARD;
×
1456
  }
1457

1458
  /**
1459
   * Test whether a script is of an unknown/non-standard type.
1460
   * @returns {Boolean}
1461
   */
1462

1463
  isUnknown() {
1464
    return this.getType() === scriptTypes.NONSTANDARD;
×
1465
  }
1466

1467
  /**
1468
   * Test whether the script is standard by policy standards.
1469
   * @returns {Boolean}
1470
   */
1471

1472
  isStandard() {
1473
    const [m, n] = this.getMultisig();
×
1474

1475
    if (m !== -1) {
×
1476
      if (n < 1 || n > 3)
×
1477
        return false;
×
1478

1479
      if (m < 1 || m > n)
×
1480
        return false;
×
1481

1482
      return true;
×
1483
    }
1484

1485
    return this.getType() !== scriptTypes.NONSTANDARD;
×
1486
  }
1487

1488
  /**
1489
   * Calculate the size of the script
1490
   * excluding the varint size bytes.
1491
   * @returns {Number}
1492
   */
1493

1494
  getSize() {
1495
    return this.raw.length;
×
1496
  }
1497

1498
  /**
1499
   * Calculate the size of the script
1500
   * including the varint size bytes.
1501
   * @returns {Number}
1502
   */
1503

1504
  getVarSize() {
1505
    return encoding.sizeVarBytes(this.raw);
16✔
1506
  }
1507

1508
  /**
1509
   * Get the sha3 of the raw script.
1510
   * @returns {Hash}
1511
   */
1512

1513
  sha3() {
1514
    return sha3.digest(this.encode());
3✔
1515
  }
1516

1517
  /**
1518
   * Test whether the output script is pay-to-pubkey.
1519
   * @param {Boolean} [minimal=false] - Minimaldata only.
1520
   * @returns {Boolean}
1521
   */
1522

1523
  isPubkey(minimal) {
1524
    if (minimal) {
32!
1525
      return this.raw.length === 35
×
1526
        && this.raw[0] === 33
1527
        && this.raw[0] + 2 === this.raw.length
1528
        && this.raw[this.raw.length - 1] === opcodes.OP_CHECKSIG;
1529
    }
1530

1531
    if (this.code.length !== 2)
32!
1532
      return false;
32✔
1533

1534
    return this.getLength(0) === 33
×
1535
      && this.getOp(1) === opcodes.OP_CHECKSIG;
1536
  }
1537

1538
  /**
1539
   * Get P2PK key if present.
1540
   * @param {Boolean} [minimal=false] - Minimaldata only.
1541
   * @returns {Buffer|null}
1542
   */
1543

1544
  getPubkey(minimal) {
1545
    if (!this.isPubkey(minimal))
32!
1546
      return null;
32✔
1547

1548
    if (minimal)
×
1549
      return this.raw.slice(1, 1 + this.raw[0]);
×
1550

1551
    return this.getData(0);
×
1552
  }
1553

1554
  /**
1555
   * Test whether the output script is pay-to-pubkeyhash.
1556
   * @param {Boolean} [minimal=false] - Minimaldata only.
1557
   * @returns {Boolean}
1558
   */
1559

1560
  isPubkeyhash(minimal) {
1561
    if (minimal || this.raw.length === 25) {
32!
1562
      return this.raw.length === 25
32✔
1563
        && this.raw[0] === opcodes.OP_DUP
1564
        && this.raw[1] === opcodes.OP_BLAKE160
1565
        && this.raw[2] === 0x14
1566
        && this.raw[23] === opcodes.OP_EQUALVERIFY
1567
        && this.raw[24] === opcodes.OP_CHECKSIG;
1568
    }
1569

UNCOV
1570
    if (this.code.length !== 5)
×
UNCOV
1571
      return false;
×
1572

UNCOV
1573
    return this.getOp(0) === opcodes.OP_DUP
×
1574
      && this.getOp(1) === opcodes.OP_BLAKE160
1575
      && this.getLength(2) === 20
1576
      && this.getOp(3) === opcodes.OP_EQUALVERIFY
1577
      && this.getOp(4) === opcodes.OP_CHECKSIG;
1578
  }
1579

1580
  /**
1581
   * Get P2PKH hash if present.
1582
   * @param {Boolean} [minimal=false] - Minimaldata only.
1583
   * @returns {Buffer|null}
1584
   */
1585

1586
  getPubkeyhash(minimal) {
1587
    if (!this.isPubkeyhash(minimal))
32!
UNCOV
1588
      return null;
×
1589

1590
    if (minimal)
32!
1591
      return this.raw.slice(3, 23);
×
1592

1593
    return this.getData(2);
32✔
1594
  }
1595

1596
  /**
1597
   * Test whether the output script is pay-to-multisig.
1598
   * @param {Boolean} [minimal=false] - Minimaldata only.
1599
   * @returns {Boolean}
1600
   */
1601

1602
  isMultisig(minimal) {
UNCOV
1603
    if (this.code.length < 4 || this.code.length > 19)
×
1604
      return false;
×
1605

UNCOV
1606
    if (this.getOp(-1) !== opcodes.OP_CHECKMULTISIG)
×
1607
      return false;
×
1608

UNCOV
1609
    const m = this.getSmall(0);
×
1610

UNCOV
1611
    if (m < 1)
×
1612
      return false;
×
1613

UNCOV
1614
    const n = this.getSmall(-2);
×
1615

UNCOV
1616
    if (n < 1 || m > n)
×
1617
      return false;
×
1618

UNCOV
1619
    if (this.code.length !== n + 3)
×
1620
      return false;
×
1621

UNCOV
1622
    for (let i = 1; i < n + 1; i++) {
×
UNCOV
1623
      const op = this.code[i];
×
1624

UNCOV
1625
      if (op.toLength() !== 33)
×
1626
        return false;
×
1627

UNCOV
1628
      if (minimal && !op.isMinimal())
×
1629
        return false;
×
1630
    }
1631

UNCOV
1632
    return true;
×
1633
  }
1634

1635
  /**
1636
   * Get multisig m and n values if present.
1637
   * @param {Boolean} [minimal=false] - Minimaldata only.
1638
   * @returns {Array} [m, n]
1639
   */
1640

1641
  getMultisig(minimal) {
UNCOV
1642
    if (!this.isMultisig(minimal))
×
1643
      return [-1, -1];
×
1644

UNCOV
1645
    return [this.getSmall(0), this.getSmall(-2)];
×
1646
  }
1647

1648
  /**
1649
   * Test whether the output script is unspendable.
1650
   * @returns {Boolean}
1651
   */
1652

1653
  isUnspendable() {
1654
    if (this.raw.length > consensus.MAX_SCRIPT_SIZE)
×
1655
      return true;
×
1656

1657
    return this.raw.length > 0 && this.raw[0] === opcodes.OP_RETURN;
×
1658
  }
1659

1660
  /**
1661
   * Test the script against a bloom filter.
1662
   * @param {BloomFilter} filter
1663
   * @returns {Boolean}
1664
   */
1665

1666
  test(filter) {
1667
    for (const op of this.code) {
×
1668
      if (op.value === -1)
×
1669
        break;
×
1670

1671
      if (!op.data || op.data.length === 0)
×
1672
        continue;
×
1673

1674
      if (filter.test(op.data))
×
1675
        return true;
×
1676
    }
1677

1678
    return false;
×
1679
  }
1680

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

1687
  isPushOnly() {
1688
    for (const op of this.code) {
×
1689
      if (op.value === -1)
×
1690
        return false;
×
1691

1692
      if (op.value > opcodes.OP_16)
×
1693
        return false;
×
1694
    }
1695

1696
    return true;
×
1697
  }
1698

1699
  /**
1700
   * Count the sigops in the script.
1701
   * @returns {Number} sigop count
1702
   */
1703

1704
  getSigops() {
UNCOV
1705
    let total = 0;
×
UNCOV
1706
    let lastOp = -1;
×
1707

UNCOV
1708
    for (const op of this.code) {
×
UNCOV
1709
      if (op.value === -1)
×
1710
        break;
×
1711

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

UNCOV
1726
      lastOp = op.value;
×
1727
    }
1728

UNCOV
1729
    return total;
×
1730
  }
1731

1732
  /*
1733
   * Mutation
1734
   */
1735

1736
  get(index) {
1737
    if (index < 0)
32!
UNCOV
1738
      index += this.code.length;
×
1739

1740
    if (index < 0 || index >= this.code.length)
32!
1741
      return null;
×
1742

1743
    return this.code[index];
32✔
1744
  }
1745

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

1751
  shift() {
1752
    const op = this.code.shift();
×
1753
    return op || null;
×
1754
  }
1755

1756
  remove(index) {
1757
    if (index < 0)
×
1758
      index += this.code.length;
×
1759

1760
    if (index < 0 || index >= this.code.length)
×
1761
      return null;
×
1762

1763
    const items = this.code.splice(index, 1);
×
1764

1765
    if (items.length === 0)
×
1766
      return null;
×
1767

1768
    return items[0];
×
1769
  }
1770

1771
  set(index, op) {
1772
    if (index < 0)
×
1773
      index += this.code.length;
×
1774

1775
    assert(Opcode.isOpcode(op));
×
1776
    assert(index >= 0 && index <= this.code.length);
×
1777

1778
    this.code[index] = op;
×
1779

1780
    return this;
×
1781
  }
1782

1783
  push(op) {
1784
    assert(Opcode.isOpcode(op));
112✔
1785
    this.code.push(op);
112✔
1786
    return this;
112✔
1787
  }
1788

1789
  unshift(op) {
1790
    assert(Opcode.isOpcode(op));
×
1791
    this.code.unshift(op);
×
1792
    return this;
×
1793
  }
1794

1795
  insert(index, op) {
1796
    if (index < 0)
×
1797
      index += this.code.length;
×
1798

1799
    assert(Opcode.isOpcode(op));
×
1800
    assert(index >= 0 && index <= this.code.length);
×
1801

1802
    this.code.splice(index, 0, op);
×
1803

1804
    return this;
×
1805
  }
1806

1807
  /*
1808
   * Op
1809
   */
1810

1811
  getOp(index) {
UNCOV
1812
    const op = this.get(index);
×
UNCOV
1813
    return op ? op.value : -1;
×
1814
  }
1815

1816
  popOp() {
1817
    const op = this.pop();
×
1818
    return op ? op.value : -1;
×
1819
  }
1820

1821
  shiftOp() {
1822
    const op = this.shift();
×
1823
    return op ? op.value : -1;
×
1824
  }
1825

1826
  removeOp(index) {
1827
    const op = this.remove(index);
×
1828
    return op ? op.value : -1;
×
1829
  }
1830

1831
  setOp(index, value) {
1832
    return this.set(index, Opcode.fromOp(value));
×
1833
  }
1834

1835
  pushOp(value) {
1836
    return this.push(Opcode.fromOp(value));
105✔
1837
  }
1838

1839
  unshiftOp(value) {
1840
    return this.unshift(Opcode.fromOp(value));
×
1841
  }
1842

1843
  insertOp(index, value) {
1844
    return this.insert(index, Opcode.fromOp(value));
×
1845
  }
1846

1847
  /*
1848
   * Data
1849
   */
1850

1851
  getData(index) {
1852
    const op = this.get(index);
32✔
1853
    return op ? op.data : null;
32!
1854
  }
1855

1856
  popData() {
1857
    const op = this.pop();
×
1858
    return op ? op.data : null;
×
1859
  }
1860

1861
  shiftData() {
1862
    const op = this.shift();
×
1863
    return op ? op.data : null;
×
1864
  }
1865

1866
  removeData(index) {
1867
    const op = this.remove(index);
×
1868
    return op ? op.data : null;
×
1869
  }
1870

1871
  setData(index, data) {
1872
    return this.set(index, Opcode.fromData(data));
×
1873
  }
1874

1875
  pushData(data) {
UNCOV
1876
    return this.push(Opcode.fromData(data));
×
1877
  }
1878

1879
  unshiftData(data) {
1880
    return this.unshift(Opcode.fromData(data));
×
1881
  }
1882

1883
  insertData(index, data) {
1884
    return this.insert(index, Opcode.fromData(data));
×
1885
  }
1886

1887
  /*
1888
   * Length
1889
   */
1890

1891
  getLength(index) {
1892
    const op = this.get(index);
×
1893
    return op ? op.toLength() : -1;
×
1894
  }
1895

1896
  /*
1897
   * Push
1898
   */
1899

1900
  getPush(index) {
1901
    const op = this.get(index);
×
1902
    return op ? op.toPush() : null;
×
1903
  }
1904

1905
  popPush() {
1906
    const op = this.pop();
×
1907
    return op ? op.toPush() : null;
×
1908
  }
1909

1910
  shiftPush() {
1911
    const op = this.shift();
×
1912
    return op ? op.toPush() : null;
×
1913
  }
1914

1915
  removePush(index) {
1916
    const op = this.remove(index);
×
1917
    return op ? op.toPush() : null;
×
1918
  }
1919

1920
  setPush(index, data) {
1921
    return this.set(index, Opcode.fromPush(data));
×
1922
  }
1923

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

1928
  unshiftPush(data) {
1929
    return this.unshift(Opcode.fromPush(data));
×
1930
  }
1931

1932
  insertPush(index, data) {
1933
    return this.insert(index, Opcode.fromPush(data));
×
1934
  }
1935

1936
  /*
1937
   * String
1938
   */
1939

1940
  getString(index, enc) {
1941
    const op = this.get(index);
×
1942
    return op ? op.toString(enc) : null;
×
1943
  }
1944

1945
  popString(enc) {
1946
    const op = this.pop();
×
1947
    return op ? op.toString(enc) : null;
×
1948
  }
1949

1950
  shiftString(enc) {
1951
    const op = this.shift();
×
1952
    return op ? op.toString(enc) : null;
×
1953
  }
1954

1955
  removeString(index, enc) {
1956
    const op = this.remove(index);
×
1957
    return op ? op.toString(enc) : null;
×
1958
  }
1959

1960
  setString(index, str, enc) {
1961
    return this.set(index, Opcode.fromString(str, enc));
×
1962
  }
1963

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

1968
  unshiftString(str, enc) {
1969
    return this.unshift(Opcode.fromString(str, enc));
×
1970
  }
1971

1972
  insertString(index, str, enc) {
1973
    return this.insert(index, Opcode.fromString(str, enc));
×
1974
  }
1975

1976
  /*
1977
   * Small
1978
   */
1979

1980
  getSmall(index) {
UNCOV
1981
    const op = this.get(index);
×
UNCOV
1982
    return op ? op.toSmall() : -1;
×
1983
  }
1984

1985
  popSmall() {
1986
    const op = this.pop();
×
1987
    return op ? op.toSmall() : -1;
×
1988
  }
1989

1990
  shiftSmall() {
1991
    const op = this.shift();
×
1992
    return op ? op.toSmall() : -1;
×
1993
  }
1994

1995
  removeSmall(index) {
1996
    const op = this.remove(index);
×
1997
    return op ? op.toSmall() : -1;
×
1998
  }
1999

2000
  setSmall(index, num) {
2001
    return this.set(index, Opcode.fromSmall(num));
×
2002
  }
2003

2004
  pushSmall(num) {
UNCOV
2005
    return this.push(Opcode.fromSmall(num));
×
2006
  }
2007

2008
  unshiftSmall(num) {
2009
    return this.unshift(Opcode.fromSmall(num));
×
2010
  }
2011

2012
  insertSmall(index, num) {
2013
    return this.insert(index, Opcode.fromSmall(num));
×
2014
  }
2015

2016
  /*
2017
   * Num
2018
   */
2019

2020
  getNum(index, minimal, limit) {
2021
    const op = this.get(index);
×
2022
    return op ? op.toNum(minimal, limit) : null;
×
2023
  }
2024

2025
  popNum(minimal, limit) {
2026
    const op = this.pop();
×
2027
    return op ? op.toNum(minimal, limit) : null;
×
2028
  }
2029

2030
  shiftNum(minimal, limit) {
2031
    const op = this.shift();
×
2032
    return op ? op.toNum(minimal, limit) : null;
×
2033
  }
2034

2035
  removeNum(index, minimal, limit) {
2036
    const op = this.remove(index);
×
2037
    return op ? op.toNum(minimal, limit) : null;
×
2038
  }
2039

2040
  setNum(index, num) {
2041
    return this.set(index, Opcode.fromNum(num));
×
2042
  }
2043

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

2048
  unshiftNum(num) {
2049
    return this.unshift(Opcode.fromNum(num));
×
2050
  }
2051

2052
  insertNum(index, num) {
2053
    return this.insert(index, Opcode.fromNum(num));
×
2054
  }
2055

2056
  /*
2057
   * Int
2058
   */
2059

2060
  getInt(index, minimal, limit) {
2061
    const op = this.get(index);
×
2062
    return op ? op.toInt(minimal, limit) : -1;
×
2063
  }
2064

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

2070
  shiftInt(minimal, limit) {
2071
    const op = this.shift();
×
2072
    return op ? op.toInt(minimal, limit) : -1;
×
2073
  }
2074

2075
  removeInt(index, minimal, limit) {
2076
    const op = this.remove(index);
×
2077
    return op ? op.toInt(minimal, limit) : -1;
×
2078
  }
2079

2080
  setInt(index, num) {
2081
    return this.set(index, Opcode.fromInt(num));
×
2082
  }
2083

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

2088
  unshiftInt(num) {
2089
    return this.unshift(Opcode.fromInt(num));
×
2090
  }
2091

2092
  insertInt(index, num) {
2093
    return this.insert(index, Opcode.fromInt(num));
×
2094
  }
2095

2096
  /*
2097
   * Bool
2098
   */
2099

2100
  getBool(index) {
2101
    const op = this.get(index);
×
2102
    return op ? op.toBool() : false;
×
2103
  }
2104

2105
  popBool() {
2106
    const op = this.pop();
×
2107
    return op ? op.toBool() : false;
×
2108
  }
2109

2110
  shiftBool() {
2111
    const op = this.shift();
×
2112
    return op ? op.toBool() : false;
×
2113
  }
2114

2115
  removeBool(index) {
2116
    const op = this.remove(index);
×
2117
    return op ? op.toBool() : false;
×
2118
  }
2119

2120
  setBool(index, value) {
2121
    return this.set(index, Opcode.fromBool(value));
×
2122
  }
2123

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

2128
  unshiftBool(value) {
2129
    return this.unshift(Opcode.fromBool(value));
×
2130
  }
2131

2132
  insertBool(index, value) {
2133
    return this.insert(index, Opcode.fromBool(value));
×
2134
  }
2135

2136
  /*
2137
   * Symbol
2138
   */
2139

2140
  getSym(index) {
2141
    const op = this.get(index);
×
2142
    return op ? op.toSymbol() : null;
×
2143
  }
2144

2145
  popSym() {
2146
    const op = this.pop();
×
2147
    return op ? op.toSymbol() : null;
×
2148
  }
2149

2150
  shiftSym() {
2151
    const op = this.shift();
×
2152
    return op ? op.toSymbol() : null;
×
2153
  }
2154

2155
  removeSym(index) {
2156
    const op = this.remove(index);
×
2157
    return op ? op.toSymbol() : null;
×
2158
  }
2159

2160
  setSym(index, symbol) {
2161
    return this.set(index, Opcode.fromSymbol(symbol));
×
2162
  }
2163

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

2168
  unshiftSym(symbol) {
2169
    return this.unshift(Opcode.fromSymbol(symbol));
×
2170
  }
2171

2172
  insertSym(index, symbol) {
2173
    return this.insert(index, Opcode.fromSymbol(symbol));
×
2174
  }
2175

2176
  /**
2177
   * Inject properties from bitcoind test string.
2178
   * @param {String} code - Script string.
2179
   * @throws Parse error.
2180
   */
2181

2182
  fromString(code) {
2183
    assert(typeof code === 'string');
876✔
2184

2185
    code = code.trim();
876✔
2186

2187
    if (code.length === 0)
876✔
2188
      return this;
4✔
2189

2190
    const items = code.split(/\s+/);
872✔
2191
    const bw = bio.write();
872✔
2192

2193
    for (const item of items) {
872✔
2194
      let symbol = item;
8,282✔
2195

2196
      if (symbol.charCodeAt(0) & 32)
8,282✔
2197
        symbol = symbol.toUpperCase();
1,690✔
2198

2199
      if (!/^OP_/.test(symbol))
8,282✔
2200
        symbol = `OP_${symbol}`;
1,690✔
2201

2202
      const value = opcodes[symbol];
8,282✔
2203

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

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

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

2222
        const hex = item.substring(2);
437✔
2223
        const data = Buffer.from(hex, 'hex');
437✔
2224

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

2227
        bw.writeBytes(data);
437✔
2228

2229
        continue;
437✔
2230
      }
2231

2232
      bw.writeU8(value);
6,592✔
2233
    }
2234

2235
    return this.decode(bw.render());
872✔
2236
  }
2237

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

2249
  static verify(witness, addr, tx, index, value, flags) {
UNCOV
2250
    if (flags == null)
×
UNCOV
2251
      flags = Script.flags.STANDARD_VERIFY_FLAGS;
×
2252

UNCOV
2253
    assert(addr.version <= 31);
×
2254

UNCOV
2255
    if (addr.version === 31)
×
2256
      throw new ScriptError('OP_RETURN');
×
2257

UNCOV
2258
    if (witness.items.length > consensus.MAX_SCRIPT_STACK)
×
2259
      throw new ScriptError('STACK_SIZE');
×
2260

UNCOV
2261
    const stack = witness.toStack();
×
2262

UNCOV
2263
    let redeem = null;
×
2264

UNCOV
2265
    if (addr.version === 0) {
×
UNCOV
2266
      if (addr.hash.length === 32) {
×
UNCOV
2267
        if (stack.length === 0)
×
2268
          throw new ScriptError('WITNESS_PROGRAM_WITNESS_EMPTY');
×
2269

UNCOV
2270
        const witnessScript = stack.pop();
×
2271

UNCOV
2272
        if (witnessScript.length > consensus.MAX_SCRIPT_SIZE)
×
2273
          throw new ScriptError('SCRIPT_SIZE');
×
2274

UNCOV
2275
        if (!sha3.digest(witnessScript).equals(addr.hash))
×
UNCOV
2276
          throw new ScriptError('WITNESS_PROGRAM_MISMATCH');
×
2277

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

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

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

2300
    // Verify the redeem script.
UNCOV
2301
    redeem.execute(stack, flags, tx, index, value);
×
2302

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

2308
  /**
2309
   * Inject properties from buffer reader.
2310
   * @param {bio.BufferReader} br
2311
   */
2312

2313
  read(br) {
2314
    return this.decode(br.readVarBytes());
×
2315
  }
2316

2317
  /**
2318
   * Inject properties from serialized data.
2319
   * @param {Buffer} data
2320
   * @returns {this}
2321
   */
2322

2323
  decode(data) {
2324
    const br = bio.read(data);
872✔
2325

2326
    this.raw = data;
872✔
2327

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

2331
    return this;
872✔
2332
  }
2333

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

2340
  static isScript(obj) {
2341
    return obj instanceof Script;
×
2342
  }
2343
}
2344

2345
/**
2346
 * Script opcodes.
2347
 * @enum {Number}
2348
 * @default
2349
 */
2350

2351
Script.opcodes = common.opcodes;
1✔
2352

2353
/**
2354
 * Opcodes by value.
2355
 * @const {RevMap}
2356
 */
2357

2358
Script.opcodesByVal = common.opcodesByVal;
1✔
2359

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

2365
Script.flags = common.flags;
1✔
2366

2367
/**
2368
 * Sighash Types.
2369
 * @enum {SighashType}
2370
 * @default
2371
 */
2372

2373
Script.hashType = common.hashType;
1✔
2374

2375
/**
2376
 * Sighash types by value.
2377
 * @const {RevMap}
2378
 */
2379

2380
Script.hashTypeByVal = common.hashTypeByVal;
1✔
2381

2382
/**
2383
 * Output script types.
2384
 * @enum {Number}
2385
 */
2386

2387
Script.types = common.types;
1✔
2388

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

2394
Script.typesByVal = common.typesByVal;
1✔
2395

2396
/*
2397
 * Helpers
2398
 */
2399

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

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

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

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

UNCOV
2421
  return true;
×
2422
}
2423

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

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

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

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

UNCOV
2447
  return true;
×
2448
}
2449

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

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

2462
/*
2463
 * Expose
2464
 */
2465

2466
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