• 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

3.73
/lib/script/stack.js
1
/*!
2
 * stack.js - stack object 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 common = require('./common');
1✔
12
const ScriptNum = require('./scriptnum');
1✔
13

14
/**
15
 * Stack
16
 * Represents the stack of a Script during execution.
17
 * @alias module:script.Stack
18
 * @property {Buffer[]} items - Stack items.
19
 * @property {Number} length - Size of stack.
20
 */
21

22
class Stack extends bio.Struct {
23
  /**
24
   * Create a stack.
25
   * @constructor
26
   * @param {Buffer[]?} items - Stack items.
27
   */
28

29
  constructor(items) {
30
    super();
1,064✔
31
    this.items = items || [];
1,064✔
32
  }
33

34
  /**
35
   * Get length.
36
   * @returns {Number}
37
   */
38

39
  get length() {
UNCOV
40
    return this.items.length;
×
41
  }
42

43
  /**
44
   * Set length.
45
   * @param {Number} value
46
   */
47

48
  set length(value) {
UNCOV
49
    this.items.length = value;
×
50
  }
51

52
  /**
53
   * Instantiate a value-only iterator.
54
   * @returns {StackIterator}
55
   */
56

57
  [Symbol.iterator]() {
58
    return this.items[Symbol.iterator]();
×
59
  }
60

61
  /**
62
   * Instantiate a value-only iterator.
63
   * @returns {StackIterator}
64
   */
65

66
  values() {
67
    return this.items.values();
×
68
  }
69

70
  /**
71
   * Instantiate a key and value iterator.
72
   * @returns {StackIterator}
73
   */
74

75
  entries() {
76
    return this.items.entries();
×
77
  }
78

79
  /**
80
   * Inspect the stack.
81
   * @returns {String} Human-readable stack.
82
   */
83

84
  format() {
85
    return `<Stack: ${this.toString()}>`;
×
86
  }
87

88
  /**
89
   * Convert the stack to a string.
90
   * @returns {String} Human-readable stack.
91
   */
92

93
  toString() {
94
    const out = [];
×
95

96
    for (const item of this.items)
×
97
      out.push(item.toString('hex'));
×
98

99
    return out.join(' ');
×
100
  }
101

102
  /**
103
   * Format the stack as bitcoind asm.
104
   * @param {Boolean?} decode - Attempt to decode hash types.
105
   * @returns {String} Human-readable script.
106
   */
107

108
  toASM(decode) {
109
    const out = [];
×
110

111
    for (const item of this.items)
×
112
      out.push(common.toASM(item, decode));
×
113

114
    return out.join(' ');
×
115
  }
116

117
  /**
118
   * Clone the stack.
119
   * @returns {Stack} Cloned stack.
120
   */
121

122
  inject(stack) {
123
    this.items = stack.items.slice();
×
124
    return this;
×
125
  }
126

127
  /**
128
   * Clear the stack.
129
   * @returns {Stack}
130
   */
131

132
  clear() {
133
    this.items.length = 0;
×
134
    return this;
×
135
  }
136

137
  /**
138
   * Get a stack item by index.
139
   * @param {Number} index
140
   * @returns {Buffer|null}
141
   */
142

143
  get(index) {
UNCOV
144
    if (index < 0)
×
UNCOV
145
      index += this.items.length;
×
146

UNCOV
147
    if (index < 0 || index >= this.items.length)
×
148
      return null;
×
149

UNCOV
150
    return this.items[index];
×
151
  }
152

153
  /**
154
   * Pop a stack item.
155
   * @see Array#pop
156
   * @returns {Buffer|null}
157
   */
158

159
  pop() {
UNCOV
160
    const item = this.items.pop();
×
UNCOV
161
    return item || null;
×
162
  }
163

164
  /**
165
   * Shift a stack item.
166
   * @see Array#shift
167
   * @returns {Buffer|null}
168
   */
169

170
  shift() {
171
    const item = this.items.shift();
×
172
    return item || null;
×
173
  }
174

175
  /**
176
   * Remove an item.
177
   * @param {Number} index
178
   * @returns {Buffer}
179
   */
180

181
  remove(index) {
UNCOV
182
    if (index < 0)
×
UNCOV
183
      index += this.items.length;
×
184

UNCOV
185
    if (index < 0 || index >= this.items.length)
×
186
      return null;
×
187

UNCOV
188
    const items = this.items.splice(index, 1);
×
189

UNCOV
190
    if (items.length === 0)
×
191
      return null;
×
192

UNCOV
193
    return items[0];
×
194
  }
195

196
  /**
197
   * Set stack item at index.
198
   * @param {Number} index
199
   * @param {Buffer} value
200
   * @returns {Buffer}
201
   */
202

203
  set(index, item) {
UNCOV
204
    if (index < 0)
×
205
      index += this.items.length;
×
206

UNCOV
207
    assert(Buffer.isBuffer(item));
×
UNCOV
208
    assert(index >= 0 && index <= this.items.length);
×
209

UNCOV
210
    this.items[index] = item;
×
211

UNCOV
212
    return this;
×
213
  }
214

215
  /**
216
   * Push item onto stack.
217
   * @see Array#push
218
   * @param {Buffer} item
219
   * @returns {Number} Stack size.
220
   */
221

222
  push(item) {
UNCOV
223
    assert(Buffer.isBuffer(item));
×
UNCOV
224
    this.items.push(item);
×
UNCOV
225
    return this;
×
226
  }
227

228
  /**
229
   * Unshift item from stack.
230
   * @see Array#unshift
231
   * @param {Buffer} item
232
   * @returns {Number}
233
   */
234

235
  unshift(item) {
236
    assert(Buffer.isBuffer(item));
×
237
    this.items.unshift(item);
×
238
    return this;
×
239
  }
240

241
  /**
242
   * Insert an item.
243
   * @param {Number} index
244
   * @param {Buffer} item
245
   * @returns {Buffer}
246
   */
247

248
  insert(index, item) {
UNCOV
249
    if (index < 0)
×
UNCOV
250
      index += this.items.length;
×
251

UNCOV
252
    assert(Buffer.isBuffer(item));
×
UNCOV
253
    assert(index >= 0 && index <= this.items.length);
×
254

UNCOV
255
    this.items.splice(index, 0, item);
×
256

UNCOV
257
    return this;
×
258
  }
259

260
  /**
261
   * Erase stack items.
262
   * @param {Number} start
263
   * @param {Number} end
264
   * @returns {Buffer[]}
265
   */
266

267
  erase(start, end) {
UNCOV
268
    if (start < 0)
×
UNCOV
269
      start = this.items.length + start;
×
270

UNCOV
271
    if (end < 0)
×
UNCOV
272
      end = this.items.length + end;
×
273

UNCOV
274
    this.items.splice(start, end - start);
×
275
  }
276

277
  /**
278
   * Swap stack values.
279
   * @param {Number} i1 - Index 1.
280
   * @param {Number} i2 - Index 2.
281
   */
282

283
  swap(i1, i2) {
UNCOV
284
    if (i1 < 0)
×
UNCOV
285
      i1 = this.items.length + i1;
×
286

UNCOV
287
    if (i2 < 0)
×
UNCOV
288
      i2 = this.items.length + i2;
×
289

UNCOV
290
    const v1 = this.items[i1];
×
UNCOV
291
    const v2 = this.items[i2];
×
292

UNCOV
293
    this.items[i1] = v2;
×
UNCOV
294
    this.items[i2] = v1;
×
295
  }
296

297
  /*
298
   * Data
299
   */
300

301
  getData(index) {
302
    return this.get(index);
×
303
  }
304

305
  popData() {
306
    return this.pop();
×
307
  }
308

309
  shiftData() {
310
    return this.shift();
×
311
  }
312

313
  removeData(index) {
314
    return this.remove(index);
×
315
  }
316

317
  setData(index, data) {
UNCOV
318
    return this.set(index, data);
×
319
  }
320

321
  pushData(data) {
UNCOV
322
    return this.push(data);
×
323
  }
324

325
  unshiftData(data) {
326
    return this.unshift(data);
×
327
  }
328

329
  insertData(index, data) {
330
    return this.insert(index, data);
×
331
  }
332

333
  /*
334
   * Length
335
   */
336

337
  getLength(index) {
338
    const item = this.get(index);
×
339
    return item ? item.length : -1;
×
340
  }
341

342
  /*
343
   * String
344
   */
345

346
  getString(index, enc) {
347
    const item = this.get(index);
×
348
    return item ? Stack.toString(item, enc) : null;
×
349
  }
350

351
  popString(enc) {
352
    const item = this.pop();
×
353
    return item ? Stack.toString(item, enc) : null;
×
354
  }
355

356
  shiftString(enc) {
357
    const item = this.shift();
×
358
    return item ? Stack.toString(item, enc) : null;
×
359
  }
360

361
  removeString(index, enc) {
362
    const item = this.remove(index);
×
363
    return item ? Stack.toString(item, enc) : null;
×
364
  }
365

366
  setString(index, str, enc) {
367
    return this.set(index, Stack.fromString(str, enc));
×
368
  }
369

370
  pushString(str, enc) {
371
    return this.push(Stack.fromString(str, enc));
×
372
  }
373

374
  unshiftString(str, enc) {
375
    return this.unshift(Stack.fromString(str, enc));
×
376
  }
377

378
  insertString(index, str, enc) {
379
    return this.insert(index, Stack.fromString(str, enc));
×
380
  }
381

382
  /*
383
   * Num
384
   */
385

386
  getNum(index, minimal, limit) {
UNCOV
387
    const item = this.get(index);
×
UNCOV
388
    return item ? Stack.toNum(item, minimal, limit) : null;
×
389
  }
390

391
  popNum(minimal, limit) {
392
    const item = this.pop();
×
393
    return item ? Stack.toNum(item, minimal, limit) : null;
×
394
  }
395

396
  shiftNum(minimal, limit) {
397
    const item = this.shift();
×
398
    return item ? Stack.toNum(item, minimal, limit) : null;
×
399
  }
400

401
  removeNum(index, minimal, limit) {
402
    const item = this.remove(index);
×
403
    return item ? Stack.toNum(item, minimal, limit) : null;
×
404
  }
405

406
  setNum(index, num) {
407
    return this.set(index, Stack.fromNum(num));
×
408
  }
409

410
  pushNum(num) {
UNCOV
411
    return this.push(Stack.fromNum(num));
×
412
  }
413

414
  unshiftNum(num) {
415
    return this.unshift(Stack.fromNum(num));
×
416
  }
417

418
  insertNum(index, num) {
419
    return this.insert(index, Stack.fromNum(num));
×
420
  }
421

422
  /*
423
   * Int
424
   */
425

426
  getInt(index, minimal, limit) {
UNCOV
427
    const item = this.get(index);
×
UNCOV
428
    return item ? Stack.toInt(item, minimal, limit) : -1;
×
429
  }
430

431
  popInt(minimal, limit) {
432
    const item = this.pop();
×
433
    return item ? Stack.toInt(item, minimal, limit) : -1;
×
434
  }
435

436
  shiftInt(minimal, limit) {
437
    const item = this.shift();
×
438
    return item ? Stack.toInt(item, minimal, limit) : -1;
×
439
  }
440

441
  removeInt(index, minimal, limit) {
442
    const item = this.remove(index);
×
443
    return item ? Stack.toInt(item, minimal, limit) : -1;
×
444
  }
445

446
  setInt(index, num) {
447
    return this.set(index, Stack.fromInt(num));
×
448
  }
449

450
  pushInt(num) {
UNCOV
451
    return this.push(Stack.fromInt(num));
×
452
  }
453

454
  unshiftInt(num) {
455
    return this.unshift(Stack.fromInt(num));
×
456
  }
457

458
  insertInt(index, num) {
459
    return this.insert(index, Stack.fromInt(num));
×
460
  }
461

462
  /*
463
   * Bool
464
   */
465

466
  getBool(index) {
UNCOV
467
    const item = this.get(index);
×
UNCOV
468
    return item ? Stack.toBool(item) : false;
×
469
  }
470

471
  popBool() {
472
    const item = this.pop();
×
473
    return item ? Stack.toBool(item) : false;
×
474
  }
475

476
  shiftBool() {
477
    const item = this.shift();
×
478
    return item ? Stack.toBool(item) : false;
×
479
  }
480

481
  removeBool(index) {
482
    const item = this.remove(index);
×
483
    return item ? Stack.toBool(item) : false;
×
484
  }
485

486
  setBool(index, value) {
487
    return this.set(index, Stack.fromBool(value));
×
488
  }
489

490
  pushBool(value) {
UNCOV
491
    return this.push(Stack.fromBool(value));
×
492
  }
493

494
  unshiftBool(value) {
495
    return this.unshift(Stack.fromBool(value));
×
496
  }
497

498
  insertBool(index, value) {
499
    return this.insert(index, Stack.fromBool(value));
×
500
  }
501

502
  /**
503
   * Test an object to see if it is a Stack.
504
   * @param {Object} obj
505
   * @returns {Boolean}
506
   */
507

508
  static isStack(obj) {
509
    return obj instanceof Stack;
×
510
  }
511

512
  /*
513
   * Encoding
514
   */
515

516
  static toString(item, enc) {
517
    assert(Buffer.isBuffer(item));
×
518
    return item.toString(enc || 'utf8');
×
519
  }
520

521
  static fromString(str, enc) {
522
    assert(typeof str === 'string');
×
523
    return Buffer.from(str, enc || 'utf8');
×
524
  }
525

526
  static toNum(item, minimal, limit) {
UNCOV
527
    return ScriptNum.decode(item, minimal, limit);
×
528
  }
529

530
  static fromNum(num) {
UNCOV
531
    assert(ScriptNum.isScriptNum(num));
×
UNCOV
532
    return num.encode();
×
533
  }
534

535
  static toInt(item, minimal, limit) {
UNCOV
536
    const num = Stack.toNum(item, minimal, limit);
×
UNCOV
537
    return num.getInt();
×
538
  }
539

540
  static fromInt(int) {
UNCOV
541
    assert(typeof int === 'number');
×
542

UNCOV
543
    if (int >= -1 && int <= 16)
×
UNCOV
544
      return common.small[int + 1];
×
545

UNCOV
546
    const num = ScriptNum.fromNumber(int);
×
547

UNCOV
548
    return Stack.fromNum(num);
×
549
  }
550

551
  static toBool(item) {
UNCOV
552
    assert(Buffer.isBuffer(item));
×
553

UNCOV
554
    for (let i = 0; i < item.length; i++) {
×
UNCOV
555
      if (item[i] !== 0) {
×
556
        // Cannot be negative zero
UNCOV
557
        if (i === item.length - 1 && item[i] === 0x80)
×
UNCOV
558
          return false;
×
UNCOV
559
        return true;
×
560
      }
561
    }
562

UNCOV
563
    return false;
×
564
  }
565

566
  static fromBool(value) {
UNCOV
567
    assert(typeof value === 'boolean');
×
UNCOV
568
    return Stack.fromInt(value ? 1 : 0);
×
569
  }
570
}
571

572
/*
573
 * Expose
574
 */
575

576
module.exports = Stack;
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