@bsv/sdk 1.4.19 → 1.4.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/package.json +1 -1
- package/dist/cjs/src/script/Spend.js +239 -42
- package/dist/cjs/src/script/Spend.js.map +1 -1
- package/dist/cjs/src/transaction/Transaction.js +5 -2
- package/dist/cjs/src/transaction/Transaction.js.map +1 -1
- package/dist/cjs/src/wallet/substrates/index.js +3 -1
- package/dist/cjs/src/wallet/substrates/index.js.map +1 -1
- package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
- package/dist/esm/src/script/Spend.js +236 -37
- package/dist/esm/src/script/Spend.js.map +1 -1
- package/dist/esm/src/transaction/Transaction.js +5 -2
- package/dist/esm/src/transaction/Transaction.js.map +1 -1
- package/dist/esm/src/wallet/substrates/index.js +1 -0
- package/dist/esm/src/wallet/substrates/index.js.map +1 -1
- package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
- package/dist/types/src/script/Spend.d.ts +7 -1
- package/dist/types/src/script/Spend.d.ts.map +1 -1
- package/dist/types/src/transaction/Transaction.d.ts +3 -1
- package/dist/types/src/transaction/Transaction.d.ts.map +1 -1
- package/dist/types/src/wallet/substrates/index.d.ts +1 -0
- package/dist/types/src/wallet/substrates/index.d.ts.map +1 -1
- package/dist/types/tsconfig.types.tsbuildinfo +1 -1
- package/dist/umd/bundle.js +1 -1
- package/docs/transaction.md +5 -1
- package/package.json +1 -1
- package/src/script/Spend.ts +253 -42
- package/src/transaction/Transaction.ts +6 -2
- package/src/transaction/__tests/Transaction.test.ts +125 -1
- package/src/wallet/substrates/index.ts +1 -0
package/dist/cjs/package.json
CHANGED
|
@@ -59,6 +59,7 @@ const requireCleanStack = true;
|
|
|
59
59
|
* @property {number} inputIndex - The index of this input in the current transaction.
|
|
60
60
|
* @property {UnlockingScript} unlockingScript - The unlocking script that unlocks the UTXO for spending.
|
|
61
61
|
* @property {number} inputSequence - The sequence number of this input.
|
|
62
|
+
* @property {number} lockTime - The lock time of the transaction.
|
|
62
63
|
*/
|
|
63
64
|
class Spend {
|
|
64
65
|
/**
|
|
@@ -90,9 +91,11 @@ class Spend {
|
|
|
90
91
|
* inputIndex: 0, // inputIndex
|
|
91
92
|
* unlockingScript: UnlockingScript.fromASM("3045... 02ab..."),
|
|
92
93
|
* inputSequence: 0xffffffff // inputSequence
|
|
94
|
+
* memoryLimit: 100000 // memoryLimit
|
|
93
95
|
* });
|
|
94
96
|
*/
|
|
95
97
|
constructor(params) {
|
|
98
|
+
var _a;
|
|
96
99
|
this.sourceTXID = params.sourceTXID;
|
|
97
100
|
this.sourceOutputIndex = params.sourceOutputIndex;
|
|
98
101
|
this.sourceSatoshis = params.sourceSatoshis;
|
|
@@ -104,6 +107,9 @@ class Spend {
|
|
|
104
107
|
this.unlockingScript = params.unlockingScript;
|
|
105
108
|
this.inputSequence = params.inputSequence;
|
|
106
109
|
this.lockTime = params.lockTime;
|
|
110
|
+
this.memoryLimit = (_a = params.memoryLimit) !== null && _a !== void 0 ? _a : 100000; // 100 MB is going to be processed by most miners by policy, but the default should protect apps against memory attacks.
|
|
111
|
+
this.stackMem = 0;
|
|
112
|
+
this.altStackMem = 0;
|
|
107
113
|
this.reset();
|
|
108
114
|
}
|
|
109
115
|
reset() {
|
|
@@ -113,9 +119,25 @@ class Spend {
|
|
|
113
119
|
this.stack = [];
|
|
114
120
|
this.altStack = [];
|
|
115
121
|
this.ifStack = [];
|
|
122
|
+
this.stackMem = 0;
|
|
123
|
+
this.altStackMem = 0;
|
|
116
124
|
}
|
|
117
125
|
step() {
|
|
118
|
-
var _a, _b, _c, _d
|
|
126
|
+
var _a, _b, _c, _d;
|
|
127
|
+
let poppedValue;
|
|
128
|
+
// If the stack (or alt stack) is over the memory limit, evaluation has failed.
|
|
129
|
+
if (this.stackMem > this.memoryLimit) {
|
|
130
|
+
this.scriptEvaluationError('Stack memory usage has exceeded ' + String(this.memoryLimit) + ' bytes');
|
|
131
|
+
return false;
|
|
132
|
+
}
|
|
133
|
+
if (this.altStackMem > this.memoryLimit) {
|
|
134
|
+
this.scriptEvaluationError('Alt stack memory usage has exceeded ' + String(this.memoryLimit) + ' bytes');
|
|
135
|
+
return false;
|
|
136
|
+
}
|
|
137
|
+
// Clear popped values after use to free memory
|
|
138
|
+
const clearPoppedValue = () => {
|
|
139
|
+
poppedValue = undefined;
|
|
140
|
+
};
|
|
119
141
|
// If the context is UnlockingScript and we have reached the end,
|
|
120
142
|
// set the context to LockingScript and zero the program counter
|
|
121
143
|
if (this.context === 'UnlockingScript' &&
|
|
@@ -245,6 +267,10 @@ class Spend {
|
|
|
245
267
|
// Non-canonical signature: R value type mismatch
|
|
246
268
|
return false;
|
|
247
269
|
}
|
|
270
|
+
if (buf[4 - 1] !== nLEnR) {
|
|
271
|
+
// Non-canonical signature: R length mismatch
|
|
272
|
+
return false;
|
|
273
|
+
}
|
|
248
274
|
if (nLEnR === 0) {
|
|
249
275
|
// Non-canonical signature: R length is zero
|
|
250
276
|
return false;
|
|
@@ -262,6 +288,10 @@ class Spend {
|
|
|
262
288
|
// Non-canonical signature: S value type mismatch
|
|
263
289
|
return false;
|
|
264
290
|
}
|
|
291
|
+
if (buf[6 + nLEnR - 1] !== nLEnS) {
|
|
292
|
+
// Non-canonical signature: S length mismatch
|
|
293
|
+
return false;
|
|
294
|
+
}
|
|
265
295
|
if (nLEnS === 0) {
|
|
266
296
|
// Non-canonical signature: S length is zero
|
|
267
297
|
return false;
|
|
@@ -355,9 +385,11 @@ class Spend {
|
|
|
355
385
|
}
|
|
356
386
|
if (!Array.isArray(operation.data)) {
|
|
357
387
|
this.stack.push([]);
|
|
388
|
+
this.stackMem += 0;
|
|
358
389
|
}
|
|
359
390
|
else {
|
|
360
391
|
this.stack.push(operation.data);
|
|
392
|
+
this.stackMem += operation.data.length;
|
|
361
393
|
}
|
|
362
394
|
}
|
|
363
395
|
else if (isScriptExecuting ||
|
|
@@ -383,6 +415,7 @@ class Spend {
|
|
|
383
415
|
n = currentOpcode - (OP_js_1.default.OP_1 - 1);
|
|
384
416
|
buf = new BigNumber_js_1.default(n).toScriptNum();
|
|
385
417
|
this.stack.push(buf);
|
|
418
|
+
this.stackMem += buf.length;
|
|
386
419
|
break;
|
|
387
420
|
case OP_js_1.default.OP_NOP:
|
|
388
421
|
case OP_js_1.default.OP_NOP2:
|
|
@@ -472,7 +505,11 @@ class Spend {
|
|
|
472
505
|
if (currentOpcode === OP_js_1.default.OP_NOTIF) {
|
|
473
506
|
fValue = !fValue;
|
|
474
507
|
}
|
|
475
|
-
this.stack.pop();
|
|
508
|
+
poppedValue = this.stack.pop();
|
|
509
|
+
if (poppedValue != null) {
|
|
510
|
+
this.stackMem -= poppedValue.length;
|
|
511
|
+
}
|
|
512
|
+
clearPoppedValue();
|
|
476
513
|
}
|
|
477
514
|
this.ifStack.push(fValue);
|
|
478
515
|
break;
|
|
@@ -495,10 +532,12 @@ class Spend {
|
|
|
495
532
|
}
|
|
496
533
|
buf = this.stacktop(-1);
|
|
497
534
|
fValue = this.castToBool(buf);
|
|
498
|
-
|
|
499
|
-
|
|
535
|
+
poppedValue = this.stack.pop();
|
|
536
|
+
if (poppedValue != null) {
|
|
537
|
+
this.stackMem -= poppedValue.length;
|
|
500
538
|
}
|
|
501
|
-
|
|
539
|
+
clearPoppedValue();
|
|
540
|
+
if (!fValue) {
|
|
502
541
|
this.scriptEvaluationError('OP_VERIFY requires the top stack value to be truthy.');
|
|
503
542
|
}
|
|
504
543
|
break;
|
|
@@ -515,20 +554,40 @@ class Spend {
|
|
|
515
554
|
if (this.stack.length < 1) {
|
|
516
555
|
this.scriptEvaluationError('OP_TOALTSTACK requires at oeast one item to be on the stack.');
|
|
517
556
|
}
|
|
518
|
-
|
|
557
|
+
poppedValue = this.stack.pop();
|
|
558
|
+
if (poppedValue != null) {
|
|
559
|
+
this.altStack.push(poppedValue);
|
|
560
|
+
this.altStackMem += poppedValue.length;
|
|
561
|
+
this.stackMem -= poppedValue.length;
|
|
562
|
+
}
|
|
563
|
+
clearPoppedValue();
|
|
519
564
|
break;
|
|
520
565
|
case OP_js_1.default.OP_FROMALTSTACK:
|
|
521
566
|
if (this.altStack.length < 1) {
|
|
522
567
|
this.scriptEvaluationError('OP_FROMALTSTACK requires at least one item to be on the stack.');
|
|
523
568
|
}
|
|
524
|
-
|
|
569
|
+
poppedValue = this.altStack.pop();
|
|
570
|
+
if (poppedValue != null) {
|
|
571
|
+
this.stack.push(poppedValue);
|
|
572
|
+
this.stackMem += poppedValue.length;
|
|
573
|
+
this.altStackMem -= poppedValue.length;
|
|
574
|
+
}
|
|
575
|
+
clearPoppedValue();
|
|
525
576
|
break;
|
|
526
577
|
case OP_js_1.default.OP_2DROP:
|
|
527
578
|
if (this.stack.length < 2) {
|
|
528
579
|
this.scriptEvaluationError('OP_2DROP requires at least two items to be on the stack.');
|
|
529
580
|
}
|
|
530
|
-
this.stack.pop();
|
|
531
|
-
|
|
581
|
+
poppedValue = this.stack.pop();
|
|
582
|
+
if (poppedValue != null) {
|
|
583
|
+
this.stackMem -= poppedValue.length;
|
|
584
|
+
}
|
|
585
|
+
clearPoppedValue();
|
|
586
|
+
poppedValue = this.stack.pop();
|
|
587
|
+
if (poppedValue != null) {
|
|
588
|
+
this.stackMem -= poppedValue.length;
|
|
589
|
+
}
|
|
590
|
+
clearPoppedValue();
|
|
532
591
|
break;
|
|
533
592
|
case OP_js_1.default.OP_2DUP:
|
|
534
593
|
if (this.stack.length < 2) {
|
|
@@ -537,7 +596,9 @@ class Spend {
|
|
|
537
596
|
buf1 = this.stacktop(-2);
|
|
538
597
|
buf2 = this.stacktop(-1);
|
|
539
598
|
this.stack.push([...buf1]);
|
|
599
|
+
this.stackMem += buf1.length;
|
|
540
600
|
this.stack.push([...buf2]);
|
|
601
|
+
this.stackMem += buf2.length;
|
|
541
602
|
break;
|
|
542
603
|
case OP_js_1.default.OP_3DUP:
|
|
543
604
|
if (this.stack.length < 3) {
|
|
@@ -547,8 +608,11 @@ class Spend {
|
|
|
547
608
|
buf2 = this.stacktop(-2);
|
|
548
609
|
buf3 = this.stacktop(-1);
|
|
549
610
|
this.stack.push([...buf1]);
|
|
611
|
+
this.stackMem += buf1.length;
|
|
550
612
|
this.stack.push([...buf2]);
|
|
613
|
+
this.stackMem += buf2.length;
|
|
551
614
|
this.stack.push([...buf3]);
|
|
615
|
+
this.stackMem += buf3.length;
|
|
552
616
|
break;
|
|
553
617
|
case OP_js_1.default.OP_2OVER:
|
|
554
618
|
if (this.stack.length < 4) {
|
|
@@ -557,7 +621,9 @@ class Spend {
|
|
|
557
621
|
buf1 = this.stacktop(-4);
|
|
558
622
|
buf2 = this.stacktop(-3);
|
|
559
623
|
this.stack.push([...buf1]);
|
|
624
|
+
this.stackMem += buf1.length;
|
|
560
625
|
this.stack.push([...buf2]);
|
|
626
|
+
this.stackMem += buf2.length;
|
|
561
627
|
break;
|
|
562
628
|
case OP_js_1.default.OP_2ROT:
|
|
563
629
|
if (this.stack.length < 6) {
|
|
@@ -565,7 +631,9 @@ class Spend {
|
|
|
565
631
|
}
|
|
566
632
|
spliced = this.stack.splice(this.stack.length - 6, 2);
|
|
567
633
|
this.stack.push(spliced[0]);
|
|
634
|
+
this.stackMem += spliced[0].length;
|
|
568
635
|
this.stack.push(spliced[1]);
|
|
636
|
+
this.stackMem += spliced[1].length;
|
|
569
637
|
break;
|
|
570
638
|
case OP_js_1.default.OP_2SWAP:
|
|
571
639
|
if (this.stack.length < 4) {
|
|
@@ -573,7 +641,9 @@ class Spend {
|
|
|
573
641
|
}
|
|
574
642
|
spliced = this.stack.splice(this.stack.length - 4, 2);
|
|
575
643
|
this.stack.push(spliced[0]);
|
|
644
|
+
this.stackMem += spliced[0].length;
|
|
576
645
|
this.stack.push(spliced[1]);
|
|
646
|
+
this.stackMem += spliced[1].length;
|
|
577
647
|
break;
|
|
578
648
|
case OP_js_1.default.OP_IFDUP:
|
|
579
649
|
if (this.stack.length < 1) {
|
|
@@ -583,35 +653,44 @@ class Spend {
|
|
|
583
653
|
fValue = this.castToBool(buf);
|
|
584
654
|
if (fValue) {
|
|
585
655
|
this.stack.push([...buf]);
|
|
656
|
+
this.stackMem += buf.length;
|
|
586
657
|
}
|
|
587
658
|
break;
|
|
588
659
|
case OP_js_1.default.OP_DEPTH:
|
|
589
660
|
buf = new BigNumber_js_1.default(this.stack.length).toScriptNum();
|
|
590
661
|
this.stack.push(buf);
|
|
662
|
+
this.stackMem += buf.length;
|
|
591
663
|
break;
|
|
592
664
|
case OP_js_1.default.OP_DROP:
|
|
593
665
|
if (this.stack.length < 1) {
|
|
594
666
|
this.scriptEvaluationError('OP_DROP requires at least one item to be on the stack.');
|
|
595
667
|
}
|
|
596
|
-
this.stack.pop();
|
|
668
|
+
poppedValue = this.stack.pop();
|
|
669
|
+
if (poppedValue != null) {
|
|
670
|
+
this.stackMem -= poppedValue.length;
|
|
671
|
+
}
|
|
672
|
+
clearPoppedValue();
|
|
597
673
|
break;
|
|
598
674
|
case OP_js_1.default.OP_DUP:
|
|
599
675
|
if (this.stack.length < 1) {
|
|
600
676
|
this.scriptEvaluationError('OP_DUP requires at least one item to be on the stack.');
|
|
601
677
|
}
|
|
602
678
|
this.stack.push([...this.stacktop(-1)]);
|
|
679
|
+
this.stackMem += this.stacktop(-1).length;
|
|
603
680
|
break;
|
|
604
681
|
case OP_js_1.default.OP_NIP:
|
|
605
682
|
if (this.stack.length < 2) {
|
|
606
683
|
this.scriptEvaluationError('OP_NIP requires at least two items to be on the stack.');
|
|
607
684
|
}
|
|
608
685
|
this.stack.splice(this.stack.length - 2, 1);
|
|
686
|
+
this.stackMem -= this.stacktop(-1).length;
|
|
609
687
|
break;
|
|
610
688
|
case OP_js_1.default.OP_OVER:
|
|
611
689
|
if (this.stack.length < 2) {
|
|
612
690
|
this.scriptEvaluationError('OP_OVER requires at least two items to be on the stack.');
|
|
613
691
|
}
|
|
614
692
|
this.stack.push([...this.stacktop(-2)]);
|
|
693
|
+
this.stackMem += this.stacktop(-2).length;
|
|
615
694
|
break;
|
|
616
695
|
case OP_js_1.default.OP_PICK:
|
|
617
696
|
case OP_js_1.default.OP_ROLL:
|
|
@@ -621,15 +700,21 @@ class Spend {
|
|
|
621
700
|
buf = this.stacktop(-1);
|
|
622
701
|
bn = BigNumber_js_1.default.fromScriptNum(buf, requireMinimalPush);
|
|
623
702
|
n = bn.toNumber();
|
|
624
|
-
this.stack.pop();
|
|
703
|
+
poppedValue = this.stack.pop();
|
|
704
|
+
if (poppedValue != null) {
|
|
705
|
+
this.stackMem -= poppedValue.length;
|
|
706
|
+
}
|
|
707
|
+
clearPoppedValue();
|
|
625
708
|
if (n < 0 || n >= this.stack.length) {
|
|
626
709
|
this.scriptEvaluationError(`${OP_js_1.default[currentOpcode]} requires the top stack element to be 0 or a positive number less than the current size of the stack.`);
|
|
627
710
|
}
|
|
628
711
|
buf = this.stacktop(-n - 1);
|
|
629
712
|
if (currentOpcode === OP_js_1.default.OP_ROLL) {
|
|
630
713
|
this.stack.splice(this.stack.length - n - 1, 1);
|
|
714
|
+
this.stackMem -= buf.length;
|
|
631
715
|
}
|
|
632
716
|
this.stack.push([...buf]);
|
|
717
|
+
this.stackMem += buf.length;
|
|
633
718
|
break;
|
|
634
719
|
case OP_js_1.default.OP_ROT:
|
|
635
720
|
if (this.stack.length < 3) {
|
|
@@ -656,6 +741,7 @@ class Spend {
|
|
|
656
741
|
this.scriptEvaluationError('OP_TUCK requires at least two items to be on the stack.');
|
|
657
742
|
}
|
|
658
743
|
this.stack.splice(this.stack.length - 2, 0, [...this.stacktop(-1)]);
|
|
744
|
+
this.stackMem += this.stacktop(-1).length;
|
|
659
745
|
break;
|
|
660
746
|
case OP_js_1.default.OP_SIZE:
|
|
661
747
|
if (this.stack.length < 1) {
|
|
@@ -663,6 +749,7 @@ class Spend {
|
|
|
663
749
|
}
|
|
664
750
|
bn = new BigNumber_js_1.default(this.stacktop(-1).length);
|
|
665
751
|
this.stack.push(bn.toScriptNum());
|
|
752
|
+
this.stackMem += bn.toScriptNum().length;
|
|
666
753
|
break;
|
|
667
754
|
case OP_js_1.default.OP_AND:
|
|
668
755
|
case OP_js_1.default.OP_OR:
|
|
@@ -693,7 +780,11 @@ class Spend {
|
|
|
693
780
|
break;
|
|
694
781
|
}
|
|
695
782
|
// And pop vch2.
|
|
696
|
-
this.stack.pop();
|
|
783
|
+
poppedValue = this.stack.pop();
|
|
784
|
+
if (poppedValue != null) {
|
|
785
|
+
this.stackMem -= poppedValue.length;
|
|
786
|
+
}
|
|
787
|
+
clearPoppedValue();
|
|
697
788
|
break;
|
|
698
789
|
case OP_js_1.default.OP_INVERT:
|
|
699
790
|
if (this.stack.length < 1) {
|
|
@@ -711,7 +802,11 @@ class Spend {
|
|
|
711
802
|
}
|
|
712
803
|
buf1 = this.stacktop(-2);
|
|
713
804
|
if (buf1.length === 0) {
|
|
714
|
-
this.stack.pop();
|
|
805
|
+
poppedValue = this.stack.pop();
|
|
806
|
+
if (poppedValue != null) {
|
|
807
|
+
this.stackMem -= poppedValue.length;
|
|
808
|
+
}
|
|
809
|
+
clearPoppedValue();
|
|
715
810
|
}
|
|
716
811
|
else {
|
|
717
812
|
bn1 = new BigNumber_js_1.default(buf1);
|
|
@@ -720,8 +815,16 @@ class Spend {
|
|
|
720
815
|
if (n < 0) {
|
|
721
816
|
this.scriptEvaluationError(`${OP_js_1.default[currentOpcode]} requires the top item on the stack not to be negative.`);
|
|
722
817
|
}
|
|
723
|
-
this.stack.pop();
|
|
724
|
-
|
|
818
|
+
poppedValue = this.stack.pop();
|
|
819
|
+
if (poppedValue != null) {
|
|
820
|
+
this.stackMem -= poppedValue.length;
|
|
821
|
+
}
|
|
822
|
+
clearPoppedValue();
|
|
823
|
+
poppedValue = this.stack.pop();
|
|
824
|
+
if (poppedValue != null) {
|
|
825
|
+
this.stackMem -= poppedValue.length;
|
|
826
|
+
}
|
|
827
|
+
clearPoppedValue();
|
|
725
828
|
let shifted;
|
|
726
829
|
if (currentOpcode === OP_js_1.default.OP_LSHIFT) {
|
|
727
830
|
shifted = bn1.ushln(n);
|
|
@@ -731,6 +834,7 @@ class Spend {
|
|
|
731
834
|
}
|
|
732
835
|
const bufShifted = padDataToSize(shifted.toArray().slice(buf1.length * -1), buf1.length);
|
|
733
836
|
this.stack.push(bufShifted);
|
|
837
|
+
this.stackMem += bufShifted.length;
|
|
734
838
|
}
|
|
735
839
|
break;
|
|
736
840
|
case OP_js_1.default.OP_EQUAL:
|
|
@@ -741,12 +845,25 @@ class Spend {
|
|
|
741
845
|
buf1 = this.stacktop(-2);
|
|
742
846
|
buf2 = this.stacktop(-1);
|
|
743
847
|
fEqual = (0, utils_js_1.toHex)(buf1) === (0, utils_js_1.toHex)(buf2);
|
|
744
|
-
this.stack.pop();
|
|
745
|
-
|
|
848
|
+
poppedValue = this.stack.pop();
|
|
849
|
+
if (poppedValue != null) {
|
|
850
|
+
this.stackMem -= poppedValue.length;
|
|
851
|
+
}
|
|
852
|
+
clearPoppedValue();
|
|
853
|
+
poppedValue = this.stack.pop();
|
|
854
|
+
if (poppedValue != null) {
|
|
855
|
+
this.stackMem -= poppedValue.length;
|
|
856
|
+
}
|
|
857
|
+
clearPoppedValue();
|
|
746
858
|
this.stack.push(fEqual ? [1] : []);
|
|
859
|
+
this.stackMem += (fEqual ? 1 : 0);
|
|
747
860
|
if (currentOpcode === OP_js_1.default.OP_EQUALVERIFY) {
|
|
748
|
-
if (
|
|
749
|
-
this.stack.pop();
|
|
861
|
+
if (this.castToBool(this.stacktop(-1))) {
|
|
862
|
+
poppedValue = this.stack.pop();
|
|
863
|
+
if (poppedValue != null) {
|
|
864
|
+
this.stackMem -= poppedValue.length;
|
|
865
|
+
}
|
|
866
|
+
clearPoppedValue();
|
|
750
867
|
}
|
|
751
868
|
else {
|
|
752
869
|
this.scriptEvaluationError('OP_EQUALVERIFY requires the top two stack items to be equal.');
|
|
@@ -786,8 +903,13 @@ class Spend {
|
|
|
786
903
|
bn = new BigNumber_js_1.default(bn.cmpn(0) !== 0 ? 1 : 0 + 0);
|
|
787
904
|
break;
|
|
788
905
|
}
|
|
789
|
-
this.stack.pop();
|
|
906
|
+
poppedValue = this.stack.pop();
|
|
907
|
+
if (poppedValue != null) {
|
|
908
|
+
this.stackMem -= poppedValue.length;
|
|
909
|
+
}
|
|
910
|
+
clearPoppedValue();
|
|
790
911
|
this.stack.push(bn.toScriptNum());
|
|
912
|
+
this.stackMem += bn.toScriptNum().length;
|
|
791
913
|
break;
|
|
792
914
|
case OP_js_1.default.OP_ADD:
|
|
793
915
|
case OP_js_1.default.OP_SUB:
|
|
@@ -867,12 +989,25 @@ class Spend {
|
|
|
867
989
|
bn = bn1.cmp(bn2) > 0 ? bn1 : bn2;
|
|
868
990
|
break;
|
|
869
991
|
}
|
|
870
|
-
this.stack.pop();
|
|
871
|
-
|
|
992
|
+
poppedValue = this.stack.pop();
|
|
993
|
+
if (poppedValue != null) {
|
|
994
|
+
this.stackMem -= poppedValue.length;
|
|
995
|
+
}
|
|
996
|
+
clearPoppedValue();
|
|
997
|
+
poppedValue = this.stack.pop();
|
|
998
|
+
if (poppedValue != null) {
|
|
999
|
+
this.stackMem -= poppedValue.length;
|
|
1000
|
+
}
|
|
1001
|
+
clearPoppedValue();
|
|
872
1002
|
this.stack.push(bn.toScriptNum());
|
|
1003
|
+
this.stackMem += bn.toScriptNum().length;
|
|
873
1004
|
if (currentOpcode === OP_js_1.default.OP_NUMEQUALVERIFY) {
|
|
874
1005
|
if (this.castToBool(this.stacktop(-1))) {
|
|
875
|
-
this.stack.pop();
|
|
1006
|
+
poppedValue = this.stack.pop();
|
|
1007
|
+
if (poppedValue != null) {
|
|
1008
|
+
this.stackMem -= poppedValue.length;
|
|
1009
|
+
}
|
|
1010
|
+
clearPoppedValue();
|
|
876
1011
|
}
|
|
877
1012
|
else {
|
|
878
1013
|
this.scriptEvaluationError('OP_NUMEQUALVERIFY requires the top stack item to be truthy.');
|
|
@@ -887,10 +1022,23 @@ class Spend {
|
|
|
887
1022
|
bn2 = BigNumber_js_1.default.fromScriptNum(this.stacktop(-2), requireMinimalPush);
|
|
888
1023
|
bn3 = BigNumber_js_1.default.fromScriptNum(this.stacktop(-1), requireMinimalPush);
|
|
889
1024
|
fValue = bn2.cmp(bn1) <= 0 && bn1.cmp(bn3) < 0;
|
|
890
|
-
this.stack.pop();
|
|
891
|
-
|
|
892
|
-
|
|
1025
|
+
poppedValue = this.stack.pop();
|
|
1026
|
+
if (poppedValue != null) {
|
|
1027
|
+
this.stackMem -= poppedValue.length;
|
|
1028
|
+
}
|
|
1029
|
+
clearPoppedValue();
|
|
1030
|
+
poppedValue = this.stack.pop();
|
|
1031
|
+
if (poppedValue != null) {
|
|
1032
|
+
this.stackMem -= poppedValue.length;
|
|
1033
|
+
}
|
|
1034
|
+
clearPoppedValue();
|
|
1035
|
+
poppedValue = this.stack.pop();
|
|
1036
|
+
if (poppedValue != null) {
|
|
1037
|
+
this.stackMem -= poppedValue.length;
|
|
1038
|
+
}
|
|
1039
|
+
clearPoppedValue();
|
|
893
1040
|
this.stack.push(fValue ? [1] : []);
|
|
1041
|
+
this.stackMem += (fValue ? 1 : 0);
|
|
894
1042
|
break;
|
|
895
1043
|
case OP_js_1.default.OP_RIPEMD160:
|
|
896
1044
|
case OP_js_1.default.OP_SHA1:
|
|
@@ -900,7 +1048,7 @@ class Spend {
|
|
|
900
1048
|
if (this.stack.length < 1) {
|
|
901
1049
|
this.scriptEvaluationError(`${OP_js_1.default[currentOpcode]} requires at least one item to be on the stack.`);
|
|
902
1050
|
}
|
|
903
|
-
let bufHash = []; //
|
|
1051
|
+
let bufHash = []; // Initialize bufHash to an empty array
|
|
904
1052
|
buf = this.stacktop(-1);
|
|
905
1053
|
if (currentOpcode === OP_js_1.default.OP_RIPEMD160) {
|
|
906
1054
|
bufHash = Hash.ripemd160(buf);
|
|
@@ -917,8 +1065,13 @@ class Spend {
|
|
|
917
1065
|
else if (currentOpcode === OP_js_1.default.OP_HASH256) {
|
|
918
1066
|
bufHash = Hash.hash256(buf);
|
|
919
1067
|
}
|
|
920
|
-
this.stack.pop();
|
|
1068
|
+
poppedValue = this.stack.pop();
|
|
1069
|
+
if (poppedValue != null) {
|
|
1070
|
+
this.stackMem -= poppedValue.length;
|
|
1071
|
+
}
|
|
1072
|
+
clearPoppedValue();
|
|
921
1073
|
this.stack.push(bufHash);
|
|
1074
|
+
this.stackMem += bufHash.length;
|
|
922
1075
|
break;
|
|
923
1076
|
}
|
|
924
1077
|
case OP_js_1.default.OP_CODESEPARATOR:
|
|
@@ -938,10 +1091,10 @@ class Spend {
|
|
|
938
1091
|
// Subset of script starting at the most recent codeseparator
|
|
939
1092
|
// CScript scriptCode(pbegincodehash, pend);
|
|
940
1093
|
if (this.context === 'UnlockingScript') {
|
|
941
|
-
subscript = new Script_js_1.default(this.unlockingScript.chunks.slice((
|
|
1094
|
+
subscript = new Script_js_1.default(this.unlockingScript.chunks.slice((_a = this.lastCodeSeparator) !== null && _a !== void 0 ? _a : 0));
|
|
942
1095
|
}
|
|
943
1096
|
else {
|
|
944
|
-
subscript = new Script_js_1.default(this.lockingScript.chunks.slice((
|
|
1097
|
+
subscript = new Script_js_1.default(this.lockingScript.chunks.slice((_b = this.lastCodeSeparator) !== null && _b !== void 0 ? _b : 0));
|
|
945
1098
|
}
|
|
946
1099
|
// Drop the signature, since there's no way for a signature to sign itself
|
|
947
1100
|
subscript.findAndDelete(new Script_js_1.default().writeBin(bufSig));
|
|
@@ -957,13 +1110,26 @@ class Spend {
|
|
|
957
1110
|
if (!fSuccess && bufSig.length > 0) {
|
|
958
1111
|
this.scriptEvaluationError(`${OP_js_1.default[currentOpcode]} failed to verify the signature, and requires an empty signature when verification fails.`);
|
|
959
1112
|
}
|
|
960
|
-
this.stack.pop();
|
|
961
|
-
|
|
1113
|
+
poppedValue = this.stack.pop();
|
|
1114
|
+
if (poppedValue != null) {
|
|
1115
|
+
this.stackMem -= poppedValue.length;
|
|
1116
|
+
}
|
|
1117
|
+
clearPoppedValue();
|
|
1118
|
+
poppedValue = this.stack.pop();
|
|
1119
|
+
if (poppedValue != null) {
|
|
1120
|
+
this.stackMem -= poppedValue.length;
|
|
1121
|
+
}
|
|
1122
|
+
clearPoppedValue();
|
|
962
1123
|
// stack.push_back(fSuccess ? vchTrue : vchFalse);
|
|
963
1124
|
this.stack.push(fSuccess ? [1] : []);
|
|
1125
|
+
this.stackMem += (fSuccess ? 1 : 0);
|
|
964
1126
|
if (currentOpcode === OP_js_1.default.OP_CHECKSIGVERIFY) {
|
|
965
1127
|
if (fSuccess) {
|
|
966
|
-
this.stack.pop();
|
|
1128
|
+
poppedValue = this.stack.pop();
|
|
1129
|
+
if (poppedValue != null) {
|
|
1130
|
+
this.stackMem -= poppedValue.length;
|
|
1131
|
+
}
|
|
1132
|
+
clearPoppedValue();
|
|
967
1133
|
}
|
|
968
1134
|
else {
|
|
969
1135
|
this.scriptEvaluationError('OP_CHECKSIGVERIFY requires that a valid signature is provided.');
|
|
@@ -1002,10 +1168,10 @@ class Spend {
|
|
|
1002
1168
|
}
|
|
1003
1169
|
// Subset of script starting at the most recent codeseparator
|
|
1004
1170
|
if (this.context === 'UnlockingScript') {
|
|
1005
|
-
subscript = new Script_js_1.default(this.unlockingScript.chunks.slice((
|
|
1171
|
+
subscript = new Script_js_1.default(this.unlockingScript.chunks.slice((_c = this.lastCodeSeparator) !== null && _c !== void 0 ? _c : 0));
|
|
1006
1172
|
}
|
|
1007
1173
|
else {
|
|
1008
|
-
subscript = new Script_js_1.default(this.lockingScript.chunks.slice((
|
|
1174
|
+
subscript = new Script_js_1.default(this.lockingScript.chunks.slice((_d = this.lastCodeSeparator) !== null && _d !== void 0 ? _d : 0));
|
|
1009
1175
|
}
|
|
1010
1176
|
// Drop the signatures, since there's no way for a signature to sign itself
|
|
1011
1177
|
for (let k = 0; k < nSigsCount; k++) {
|
|
@@ -1051,7 +1217,11 @@ class Spend {
|
|
|
1051
1217
|
if (ikey2 > 0) {
|
|
1052
1218
|
ikey2--;
|
|
1053
1219
|
}
|
|
1054
|
-
this.stack.pop();
|
|
1220
|
+
poppedValue = this.stack.pop();
|
|
1221
|
+
if (poppedValue != null) {
|
|
1222
|
+
this.stackMem -= poppedValue.length;
|
|
1223
|
+
}
|
|
1224
|
+
clearPoppedValue();
|
|
1055
1225
|
}
|
|
1056
1226
|
// A bug causes CHECKMULTISIG to consume one extra argument
|
|
1057
1227
|
// whose contents were not checked in any way.
|
|
@@ -1066,11 +1236,20 @@ class Spend {
|
|
|
1066
1236
|
// NOTE: Is this necessary? We don't care about malleability.
|
|
1067
1237
|
this.scriptEvaluationError(`${OP_js_1.default[currentOpcode]} requires the extra stack item to be empty.`);
|
|
1068
1238
|
}
|
|
1069
|
-
this.stack.pop();
|
|
1239
|
+
poppedValue = this.stack.pop();
|
|
1240
|
+
if (poppedValue != null) {
|
|
1241
|
+
this.stackMem -= poppedValue.length;
|
|
1242
|
+
}
|
|
1243
|
+
clearPoppedValue();
|
|
1070
1244
|
this.stack.push(fSuccess ? [1] : []);
|
|
1245
|
+
this.stackMem += (fSuccess ? 1 : 0);
|
|
1071
1246
|
if (currentOpcode === OP_js_1.default.OP_CHECKMULTISIGVERIFY) {
|
|
1072
1247
|
if (fSuccess) {
|
|
1073
|
-
this.stack.pop();
|
|
1248
|
+
poppedValue = this.stack.pop();
|
|
1249
|
+
if (poppedValue != null) {
|
|
1250
|
+
this.stackMem -= poppedValue.length;
|
|
1251
|
+
}
|
|
1252
|
+
clearPoppedValue();
|
|
1074
1253
|
}
|
|
1075
1254
|
else {
|
|
1076
1255
|
this.scriptEvaluationError('OP_CHECKMULTISIGVERIFY requires that a sufficient number of valid signatures are provided.');
|
|
@@ -1087,7 +1266,14 @@ class Spend {
|
|
|
1087
1266
|
this.scriptEvaluationError(`It's not currently possible to push data larger than ${maxScriptElementSize} bytes.`);
|
|
1088
1267
|
}
|
|
1089
1268
|
this.stack[this.stack.length - 2] = [...buf1, ...buf2];
|
|
1090
|
-
this.
|
|
1269
|
+
this.stackMem -= buf1.length;
|
|
1270
|
+
this.stackMem -= buf2.length;
|
|
1271
|
+
this.stackMem += buf1.length + buf2.length;
|
|
1272
|
+
poppedValue = this.stack.pop();
|
|
1273
|
+
if (poppedValue != null) {
|
|
1274
|
+
this.stackMem -= poppedValue.length;
|
|
1275
|
+
}
|
|
1276
|
+
clearPoppedValue();
|
|
1091
1277
|
break;
|
|
1092
1278
|
case OP_js_1.default.OP_SPLIT:
|
|
1093
1279
|
if (this.stack.length < 2) {
|
|
@@ -1105,7 +1291,10 @@ class Spend {
|
|
|
1105
1291
|
buf2 = [...buf1];
|
|
1106
1292
|
// Replace existing stack values by the new values.
|
|
1107
1293
|
this.stack[this.stack.length - 2] = buf2.slice(0, n);
|
|
1294
|
+
this.stackMem -= buf1.length;
|
|
1295
|
+
this.stackMem += n;
|
|
1108
1296
|
this.stack[this.stack.length - 1] = buf2.slice(n);
|
|
1297
|
+
this.stackMem += buf1.length - n;
|
|
1109
1298
|
break;
|
|
1110
1299
|
case OP_js_1.default.OP_NUM2BIN:
|
|
1111
1300
|
if (this.stack.length < 2) {
|
|
@@ -1115,7 +1304,11 @@ class Spend {
|
|
|
1115
1304
|
if (size > maxScriptElementSize) {
|
|
1116
1305
|
this.scriptEvaluationError(`It's not currently possible to push data larger than ${maxScriptElementSize} bytes.`);
|
|
1117
1306
|
}
|
|
1118
|
-
this.stack.pop();
|
|
1307
|
+
poppedValue = this.stack.pop();
|
|
1308
|
+
if (poppedValue != null) {
|
|
1309
|
+
this.stackMem -= poppedValue.length;
|
|
1310
|
+
}
|
|
1311
|
+
clearPoppedValue();
|
|
1119
1312
|
rawnum = this.stacktop(-1);
|
|
1120
1313
|
// Try to see if we can fit that number in the number of
|
|
1121
1314
|
// byte requested.
|
|
@@ -1145,6 +1338,8 @@ class Spend {
|
|
|
1145
1338
|
}
|
|
1146
1339
|
num[n] = signbit;
|
|
1147
1340
|
this.stack[this.stack.length - 1] = num;
|
|
1341
|
+
this.stackMem -= rawnum.length;
|
|
1342
|
+
this.stackMem += size;
|
|
1148
1343
|
break;
|
|
1149
1344
|
case OP_js_1.default.OP_BIN2NUM:
|
|
1150
1345
|
if (this.stack.length < 1) {
|
|
@@ -1153,6 +1348,8 @@ class Spend {
|
|
|
1153
1348
|
buf1 = this.stacktop(-1);
|
|
1154
1349
|
buf2 = (0, utils_js_1.minimallyEncode)(buf1);
|
|
1155
1350
|
this.stack[this.stack.length - 1] = buf2;
|
|
1351
|
+
this.stackMem -= buf1.length;
|
|
1352
|
+
this.stackMem += buf2.length;
|
|
1156
1353
|
// The resulting number must be a valid number.
|
|
1157
1354
|
if (!isMinimallyEncoded(buf2)) {
|
|
1158
1355
|
this.scriptEvaluationError('OP_BIN2NUM requires that the resulting number is valid.');
|
|
@@ -1164,6 +1361,7 @@ class Spend {
|
|
|
1164
1361
|
}
|
|
1165
1362
|
// Finally, increment the program counter
|
|
1166
1363
|
this.programCounter++;
|
|
1364
|
+
return true;
|
|
1167
1365
|
}
|
|
1168
1366
|
/**
|
|
1169
1367
|
* @method validate
|
|
@@ -1180,8 +1378,7 @@ class Spend {
|
|
|
1180
1378
|
if (requirePushOnlyUnlockingScripts && !this.unlockingScript.isPushOnly()) {
|
|
1181
1379
|
this.scriptEvaluationError('Unlocking scripts can only contain push operations, and no other opcodes.');
|
|
1182
1380
|
}
|
|
1183
|
-
while (
|
|
1184
|
-
this.step();
|
|
1381
|
+
while (this.step()) {
|
|
1185
1382
|
if (this.context === 'LockingScript' &&
|
|
1186
1383
|
this.programCounter >= this.lockingScript.chunks.length) {
|
|
1187
1384
|
break;
|