1 | 'use strict';
|
2 |
|
3 | var _ = require('lodash');
|
4 |
|
5 | var Script = require('./script');
|
6 | var Opcode = require('../opcode');
|
7 | var BN = require('../crypto/bn');
|
8 | var Hash = require('../crypto/hash');
|
9 | var Signature = require('../crypto/signature');
|
10 | var PublicKey = require('../publickey');
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 | var Interpreter = function Interpreter(obj) {
|
23 | if (!(this instanceof Interpreter)) {
|
24 | return new Interpreter(obj);
|
25 | }
|
26 | if (obj) {
|
27 | this.initialize();
|
28 | this.set(obj);
|
29 | } else {
|
30 | this.initialize();
|
31 | }
|
32 | };
|
33 |
|
34 | Interpreter.SIGVERSION_BASE = 0;
|
35 | Interpreter.SIGVERSION_WITNESS_V0 = 1;
|
36 | Interpreter.SIGVERSION_TAPROOT = 2;
|
37 | Interpreter.SIGVERSION_TAPSCRIPT = 3;
|
38 |
|
39 | Interpreter.prototype.verifyWitnessProgram = function(version, program, witness, satoshis, flags) {
|
40 |
|
41 | var scriptPubKey = new Script();
|
42 | var stack = [];
|
43 |
|
44 | if (version === 0) {
|
45 | if (program.length === 32) {
|
46 | if (witness.length === 0) {
|
47 | this.errstr = 'SCRIPT_ERR_WITNESS_PROGRAM_WITNESS_EMPTY';
|
48 | return false;
|
49 | }
|
50 |
|
51 | var scriptPubKeyBuffer = witness[witness.length - 1];
|
52 | scriptPubKey = new Script(scriptPubKeyBuffer);
|
53 | var hash = Hash.sha256(scriptPubKeyBuffer);
|
54 | if (hash.toString('hex') !== program.toString('hex')) {
|
55 | this.errstr = 'SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH';
|
56 | return false;
|
57 | }
|
58 |
|
59 | stack = witness.slice(0, -1);
|
60 | } else if (program.length === 20) {
|
61 | if (witness.length !== 2) {
|
62 | this.errstr = 'SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH';
|
63 | return false;
|
64 | }
|
65 |
|
66 | scriptPubKey.add(Opcode.OP_DUP);
|
67 | scriptPubKey.add(Opcode.OP_HASH160);
|
68 | scriptPubKey.add(program);
|
69 | scriptPubKey.add(Opcode.OP_EQUALVERIFY);
|
70 | scriptPubKey.add(Opcode.OP_CHECKSIG);
|
71 |
|
72 | stack = witness;
|
73 |
|
74 | } else {
|
75 | this.errstr = 'SCRIPT_ERR_WITNESS_PROGRAM_WRONG_LENGTH';
|
76 | return false;
|
77 | }
|
78 | } else if ((flags & Interpreter.SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM)) {
|
79 | this.errstr = 'SCRIPT_ERR_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM';
|
80 | return false;
|
81 | } else {
|
82 | return true;
|
83 | }
|
84 |
|
85 | this.initialize();
|
86 |
|
87 | this.set({
|
88 | script: scriptPubKey,
|
89 | stack: stack,
|
90 | sigversion: Interpreter.SIGVERSION_WITNESS_V0,
|
91 | satoshis: satoshis,
|
92 | flags: flags,
|
93 | });
|
94 |
|
95 | if (!this.evaluate()) {
|
96 | return false;
|
97 | }
|
98 |
|
99 | if (this.stack.length !== 1) {
|
100 | this.errstr = 'SCRIPT_ERR_EVAL_FALSE';
|
101 | return false;
|
102 | }
|
103 |
|
104 | var buf = this.stack[this.stack.length - 1];
|
105 | if (!Interpreter.castToBool(buf)) {
|
106 | this.errstr = 'SCRIPT_ERR_EVAL_FALSE_IN_STACK';
|
107 | return false;
|
108 | }
|
109 |
|
110 | return true;
|
111 | };
|
112 |
|
113 |
|
114 |
|
115 |
|
116 |
|
117 |
|
118 |
|
119 |
|
120 |
|
121 |
|
122 |
|
123 |
|
124 |
|
125 |
|
126 |
|
127 |
|
128 |
|
129 |
|
130 | Interpreter.prototype.verify = function(scriptSig, scriptPubkey, tx, nin, flags, witness, satoshis) {
|
131 |
|
132 | var Transaction = require('../transaction');
|
133 | if (_.isUndefined(tx)) {
|
134 | tx = new Transaction();
|
135 | }
|
136 | if (_.isUndefined(nin)) {
|
137 | nin = 0;
|
138 | }
|
139 | if (_.isUndefined(flags)) {
|
140 | flags = 0;
|
141 | }
|
142 | if (_.isUndefined(witness)) {
|
143 | witness = null;
|
144 | }
|
145 | if (_.isUndefined(satoshis)) {
|
146 | satoshis = 0;
|
147 | }
|
148 |
|
149 | this.set({
|
150 | script: scriptSig,
|
151 | tx: tx,
|
152 | nin: nin,
|
153 | sigversion: Interpreter.SIGVERSION_BASE,
|
154 | satoshis: 0,
|
155 | flags: flags
|
156 | });
|
157 | var stackCopy;
|
158 |
|
159 | if ((flags & Interpreter.SCRIPT_VERIFY_SIGPUSHONLY) !== 0 && !scriptSig.isPushOnly()) {
|
160 | this.errstr = 'SCRIPT_ERR_SIG_PUSHONLY';
|
161 | return false;
|
162 | }
|
163 |
|
164 |
|
165 | if (!this.evaluate()) {
|
166 | return false;
|
167 | }
|
168 |
|
169 | if (flags & Interpreter.SCRIPT_VERIFY_P2SH) {
|
170 | stackCopy = this.stack.slice();
|
171 | }
|
172 |
|
173 | var stack = this.stack;
|
174 | this.initialize();
|
175 | this.set({
|
176 | script: scriptPubkey,
|
177 | stack: stack,
|
178 | tx: tx,
|
179 | nin: nin,
|
180 | flags: flags
|
181 | });
|
182 |
|
183 |
|
184 | if (!this.evaluate()) {
|
185 | return false;
|
186 | }
|
187 |
|
188 | if (this.stack.length === 0) {
|
189 | this.errstr = 'SCRIPT_ERR_EVAL_FALSE_NO_RESULT';
|
190 | return false;
|
191 | }
|
192 |
|
193 | var buf = this.stack[this.stack.length - 1];
|
194 | if (!Interpreter.castToBool(buf)) {
|
195 | this.errstr = 'SCRIPT_ERR_EVAL_FALSE_IN_STACK';
|
196 | return false;
|
197 | }
|
198 |
|
199 | var hadWitness = false;
|
200 | if ((flags & Interpreter.SCRIPT_VERIFY_WITNESS)) {
|
201 | var witnessValues = {};
|
202 | if (scriptPubkey.isWitnessProgram(witnessValues)) {
|
203 | hadWitness = true;
|
204 | if (scriptSig.toBuffer().length !== 0) {
|
205 | return false;
|
206 | }
|
207 | if (!this.verifyWitnessProgram(witnessValues.version, witnessValues.program, witness, satoshis, this.flags)) {
|
208 | return false;
|
209 | }
|
210 | }
|
211 | }
|
212 |
|
213 |
|
214 | if ((flags & Interpreter.SCRIPT_VERIFY_P2SH) && scriptPubkey.isScriptHashOut()) {
|
215 |
|
216 | if (!scriptSig.isPushOnly()) {
|
217 | this.errstr = 'SCRIPT_ERR_SIG_PUSHONLY';
|
218 | return false;
|
219 | }
|
220 |
|
221 |
|
222 |
|
223 |
|
224 | if (stackCopy.length === 0) {
|
225 | throw new Error('internal error - stack copy empty');
|
226 | }
|
227 |
|
228 | var redeemScriptSerialized = stackCopy[stackCopy.length - 1];
|
229 | var redeemScript = Script.fromBuffer(redeemScriptSerialized);
|
230 | stackCopy.pop();
|
231 |
|
232 | this.initialize();
|
233 | this.set({
|
234 | script: redeemScript,
|
235 | stack: stackCopy,
|
236 | tx: tx,
|
237 | nin: nin,
|
238 | flags: flags
|
239 | });
|
240 |
|
241 |
|
242 | if (!this.evaluate()) {
|
243 | return false;
|
244 | }
|
245 |
|
246 | if (stackCopy.length === 0) {
|
247 | this.errstr = 'SCRIPT_ERR_EVAL_FALSE_NO_P2SH_STACK';
|
248 | return false;
|
249 | }
|
250 |
|
251 | if (!Interpreter.castToBool(stackCopy[stackCopy.length - 1])) {
|
252 | this.errstr = 'SCRIPT_ERR_EVAL_FALSE_IN_P2SH_STACK';
|
253 | return false;
|
254 | }
|
255 | if ((flags & Interpreter.SCRIPT_VERIFY_WITNESS)) {
|
256 | var p2shWitnessValues = {};
|
257 | if (redeemScript.isWitnessProgram(p2shWitnessValues)) {
|
258 | hadWitness = true;
|
259 | var redeemScriptPush = new Script();
|
260 | redeemScriptPush.add(redeemScript.toBuffer());
|
261 | if (scriptSig.toHex() !== redeemScriptPush.toHex()) {
|
262 | this.errstr = 'SCRIPT_ERR_WITNESS_MALLEATED_P2SH';
|
263 | return false;
|
264 | }
|
265 |
|
266 | if (!this.verifyWitnessProgram(p2shWitnessValues.version, p2shWitnessValues.program, witness, satoshis, this.flags)) {
|
267 | return false;
|
268 | }
|
269 |
|
270 |
|
271 | stack = [stack[0]];
|
272 | }
|
273 | }
|
274 | }
|
275 |
|
276 |
|
277 |
|
278 |
|
279 |
|
280 | if ((this.flags & Interpreter.SCRIPT_VERIFY_CLEANSTACK) != 0) {
|
281 |
|
282 |
|
283 |
|
284 | if ((this.flags & Interpreter.SCRIPT_VERIFY_P2SH) == 0)
|
285 | throw 'flags & SCRIPT_VERIFY_P2SH';
|
286 |
|
287 | if (stackCopy.length != 1) {
|
288 | this.errstr = 'SCRIPT_ERR_CLEANSTACK';
|
289 | return false;
|
290 | }
|
291 | }
|
292 |
|
293 | if ((this.flags & Interpreter.SCRIPT_VERIFY_WITNESS)) {
|
294 | if (!hadWitness && witness.length > 0) {
|
295 | this.errstr = 'SCRIPT_ERR_WITNESS_UNEXPECTED';
|
296 | return false;
|
297 | }
|
298 | }
|
299 |
|
300 | return true;
|
301 | };
|
302 |
|
303 | module.exports = Interpreter;
|
304 |
|
305 | Interpreter.prototype.initialize = function(obj) {
|
306 | this.stack = [];
|
307 | this.altstack = [];
|
308 | this.pc = 0;
|
309 | this.satoshis = 0;
|
310 | this.sigversion = Interpreter.SIGVERSION_BASE;
|
311 | this.pbegincodehash = 0;
|
312 | this.nOpCount = 0;
|
313 | this.vfExec = [];
|
314 | this.errstr = '';
|
315 | this.flags = 0;
|
316 | };
|
317 |
|
318 | Interpreter.prototype.set = function(obj) {
|
319 | this.script = obj.script || this.script;
|
320 | this.tx = obj.tx || this.tx;
|
321 | this.nin = typeof obj.nin !== 'undefined' ? obj.nin : this.nin;
|
322 | this.stack = obj.stack || this.stack;
|
323 | this.altstack = obj.altack || this.altstack;
|
324 | this.pc = typeof obj.pc !== 'undefined' ? obj.pc : this.pc;
|
325 | this.pbegincodehash = typeof obj.pbegincodehash !== 'undefined' ? obj.pbegincodehash : this.pbegincodehash;
|
326 | this.sigversion = typeof obj.sigversion !== 'undefined' ? obj.sigversion : this.sigversion;
|
327 | this.satoshis = typeof obj.satoshis !== 'undefined' ? obj.satoshis : this.satoshis;
|
328 | this.nOpCount = typeof obj.nOpCount !== 'undefined' ? obj.nOpCount : this.nOpCount;
|
329 | this.vfExec = obj.vfExec || this.vfExec;
|
330 | this.errstr = obj.errstr || this.errstr;
|
331 | this.flags = typeof obj.flags !== 'undefined' ? obj.flags : this.flags;
|
332 | };
|
333 |
|
334 | Interpreter.true = Buffer.from([1]);
|
335 | Interpreter.false = Buffer.from([]);
|
336 |
|
337 | Interpreter.MAX_SCRIPT_ELEMENT_SIZE = 520;
|
338 |
|
339 | Interpreter.LOCKTIME_THRESHOLD = 500000000;
|
340 | Interpreter.LOCKTIME_THRESHOLD_BN = new BN(Interpreter.LOCKTIME_THRESHOLD);
|
341 |
|
342 |
|
343 |
|
344 | Interpreter.SCRIPT_VERIFY_NONE = 0;
|
345 |
|
346 |
|
347 | Interpreter.SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM = (1 << 12);
|
348 |
|
349 |
|
350 | Interpreter.SCRIPT_VERIFY_P2SH = (1 << 0);
|
351 |
|
352 |
|
353 |
|
354 |
|
355 | Interpreter.SCRIPT_VERIFY_STRICTENC = (1 << 1);
|
356 |
|
357 |
|
358 | Interpreter.SCRIPT_VERIFY_DERSIG = (1 << 2);
|
359 |
|
360 |
|
361 |
|
362 | Interpreter.SCRIPT_VERIFY_LOW_S = (1 << 3);
|
363 |
|
364 |
|
365 | Interpreter.SCRIPT_VERIFY_NULLDUMMY = (1 << 4);
|
366 |
|
367 |
|
368 | Interpreter.SCRIPT_VERIFY_SIGPUSHONLY = (1 << 5);
|
369 |
|
370 |
|
371 |
|
372 |
|
373 |
|
374 |
|
375 | Interpreter.SCRIPT_VERIFY_MINIMALDATA = (1 << 6);
|
376 |
|
377 |
|
378 |
|
379 |
|
380 |
|
381 |
|
382 |
|
383 |
|
384 |
|
385 | Interpreter.SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS = (1 << 7);
|
386 |
|
387 |
|
388 |
|
389 |
|
390 |
|
391 |
|
392 |
|
393 |
|
394 |
|
395 | Interpreter.SCRIPT_VERIFY_CLEANSTACK = (1 << 8),
|
396 |
|
397 |
|
398 | Interpreter.SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY = (1 << 9);
|
399 | Interpreter.SCRIPT_VERIFY_WITNESS = (1 << 10);
|
400 | Interpreter.SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS = (1 << 11);
|
401 |
|
402 |
|
403 |
|
404 |
|
405 | Interpreter.SCRIPT_VERIFY_CHECKSEQUENCEVERIFY = (1 << 10);
|
406 |
|
407 |
|
408 |
|
409 |
|
410 |
|
411 | Interpreter.SCRIPT_VERIFY_MINIMALIF = (1 << 13);
|
412 |
|
413 |
|
414 |
|
415 |
|
416 | Interpreter.SCRIPT_VERIFY_NULLFAIL = (1 << 14);
|
417 |
|
418 |
|
419 |
|
420 | Interpreter.SCRIPT_VERIFY_WITNESS_PUBKEYTYPE = (1 << 15);
|
421 |
|
422 |
|
423 |
|
424 | Interpreter.SCRIPT_ENABLE_SIGHASH_FORKID = (1 << 16);
|
425 |
|
426 |
|
427 |
|
428 | Interpreter.SCRIPT_ENABLE_REPLAY_PROTECTION = (1 << 17);
|
429 |
|
430 |
|
431 |
|
432 | Interpreter.SCRIPT_ENABLE_MONOLITH_OPCODES = (1 << 18);
|
433 |
|
434 |
|
435 |
|
436 |
|
437 |
|
438 |
|
439 |
|
440 |
|
441 | Interpreter.SEQUENCE_LOCKTIME_DISABLE_FLAG = (1 << 31);
|
442 |
|
443 |
|
444 |
|
445 |
|
446 |
|
447 |
|
448 | Interpreter.SEQUENCE_LOCKTIME_TYPE_FLAG = (1 << 22);
|
449 |
|
450 |
|
451 |
|
452 |
|
453 |
|
454 | Interpreter.SEQUENCE_LOCKTIME_MASK = 0x0000ffff;
|
455 |
|
456 |
|
457 | Interpreter.castToBool = function(buf) {
|
458 | for (var i = 0; i < buf.length; i++) {
|
459 | if (buf[i] !== 0) {
|
460 |
|
461 | if (i === buf.length - 1 && buf[i] === 0x80) {
|
462 | return false;
|
463 | }
|
464 | return true;
|
465 | }
|
466 | }
|
467 | return false;
|
468 | };
|
469 |
|
470 |
|
471 |
|
472 |
|
473 | Interpreter.prototype.checkSignatureEncoding = function(buf) {
|
474 | var sig;
|
475 |
|
476 |
|
477 |
|
478 | if (buf.length == 0) {
|
479 | return true;
|
480 | }
|
481 |
|
482 | if ((this.flags & (Interpreter.SCRIPT_VERIFY_DERSIG | Interpreter.SCRIPT_VERIFY_LOW_S | Interpreter.SCRIPT_VERIFY_STRICTENC)) !== 0 && !Signature.isTxDER(buf)) {
|
483 | this.errstr = 'SCRIPT_ERR_SIG_DER_INVALID_FORMAT';
|
484 | return false;
|
485 | } else if ((this.flags & Interpreter.SCRIPT_VERIFY_LOW_S) !== 0) {
|
486 | sig = Signature.fromTxFormat(buf);
|
487 | if (!sig.hasLowS()) {
|
488 | this.errstr = 'SCRIPT_ERR_SIG_DER_HIGH_S';
|
489 | return false;
|
490 | }
|
491 | } else if ((this.flags & Interpreter.SCRIPT_VERIFY_STRICTENC) !== 0) {
|
492 | sig = Signature.fromTxFormat(buf);
|
493 | if (!sig.hasDefinedHashtype()) {
|
494 | this.errstr = 'SCRIPT_ERR_SIG_HASHTYPE';
|
495 | return false;
|
496 | }
|
497 | }
|
498 |
|
499 | return true;
|
500 | };
|
501 |
|
502 |
|
503 |
|
504 |
|
505 | Interpreter.prototype.checkPubkeyEncoding = function(buf) {
|
506 | if ((this.flags & Interpreter.SCRIPT_VERIFY_STRICTENC) !== 0 && !PublicKey.isValid(buf)) {
|
507 | this.errstr = 'SCRIPT_ERR_PUBKEYTYPE';
|
508 | return false;
|
509 | }
|
510 |
|
511 |
|
512 | if ((this.flags & Interpreter.SCRIPT_VERIFY_WITNESS_PUBKEYTYPE) != 0 && this.sigversion == Interpreter.SIGVERSION_WITNESS_V0 && !PublicKey.fromBuffer(buf).compressed) {
|
513 | this.errstr = 'SCRIPT_ERR_WITNESS_PUBKEYTYPE';
|
514 | return false;
|
515 | }
|
516 |
|
517 | return true;
|
518 | };
|
519 |
|
520 |
|
521 |
|
522 |
|
523 |
|
524 |
|
525 | Interpreter.prototype.evaluate = function() {
|
526 | if (this.script.toBuffer().length > 10000) {
|
527 | this.errstr = 'SCRIPT_ERR_SCRIPT_SIZE';
|
528 | return false;
|
529 | }
|
530 |
|
531 | try {
|
532 | while (this.pc < this.script.chunks.length) {
|
533 | var fSuccess = this.step();
|
534 | if (!fSuccess) {
|
535 | return false;
|
536 | }
|
537 | }
|
538 |
|
539 |
|
540 | if (this.stack.length + this.altstack.length > 1000) {
|
541 | this.errstr = 'SCRIPT_ERR_STACK_SIZE';
|
542 | return false;
|
543 | }
|
544 | } catch (e) {
|
545 | this.errstr = 'SCRIPT_ERR_UNKNOWN_ERROR: ' + e;
|
546 | return false;
|
547 | }
|
548 |
|
549 | if (this.vfExec.length > 0) {
|
550 | this.errstr = 'SCRIPT_ERR_UNBALANCED_CONDITIONAL';
|
551 | return false;
|
552 | }
|
553 |
|
554 | return true;
|
555 | };
|
556 |
|
557 |
|
558 |
|
559 |
|
560 |
|
561 |
|
562 |
|
563 |
|
564 |
|
565 |
|
566 |
|
567 |
|
568 |
|
569 | Interpreter.prototype.checkLockTime = function(nLockTime) {
|
570 |
|
571 |
|
572 |
|
573 |
|
574 | if (!(
|
575 | (this.tx.nLockTime < Interpreter.LOCKTIME_THRESHOLD && nLockTime.lt(Interpreter.LOCKTIME_THRESHOLD_BN)) ||
|
576 | (this.tx.nLockTime >= Interpreter.LOCKTIME_THRESHOLD && nLockTime.gte(Interpreter.LOCKTIME_THRESHOLD_BN))
|
577 | )) {
|
578 | return false;
|
579 | }
|
580 |
|
581 |
|
582 |
|
583 | if (nLockTime.gt(new BN(this.tx.nLockTime))) {
|
584 | return false;
|
585 | }
|
586 |
|
587 |
|
588 |
|
589 |
|
590 |
|
591 |
|
592 |
|
593 |
|
594 |
|
595 |
|
596 |
|
597 | if (!this.tx.inputs[this.nin].isFinal()) {
|
598 | return false;
|
599 | }
|
600 |
|
601 | return true;
|
602 | }
|
603 |
|
604 |
|
605 |
|
606 |
|
607 |
|
608 |
|
609 |
|
610 |
|
611 | Interpreter.prototype.checkSequence = function(nSequence) {
|
612 |
|
613 |
|
614 |
|
615 | var txToSequence = this.tx.inputs[this.nin].sequenceNumber;
|
616 |
|
617 |
|
618 |
|
619 | if (this.tx.version < 2) {
|
620 | return false;
|
621 | }
|
622 |
|
623 |
|
624 |
|
625 |
|
626 |
|
627 | if (txToSequence & SEQUENCE_LOCKTIME_DISABLE_FLAG) {
|
628 | return false;
|
629 | }
|
630 |
|
631 |
|
632 |
|
633 | var nLockTimeMask =
|
634 | Interpreter.SEQUENCE_LOCKTIME_TYPE_FLAG | Interpreter.SEQUENCE_LOCKTIME_MASK;
|
635 | var txToSequenceMasked = new BN(txToSequence & nLockTimeMask);
|
636 | var nSequenceMasked = nSequence.and(nLockTimeMask);
|
637 |
|
638 |
|
639 |
|
640 |
|
641 |
|
642 |
|
643 |
|
644 |
|
645 | var SEQUENCE_LOCKTIME_TYPE_FLAG_BN = new BN(Interpreter.SEQUENCE_LOCKTIME_TYPE_FLAG);
|
646 |
|
647 | if (!((txToSequenceMasked.lt(SEQUENCE_LOCKTIME_TYPE_FLAG_BN) &&
|
648 | nSequenceMasked.lt(SEQUENCE_LOCKTIME_TYPE_FLAG_BN)) ||
|
649 | (txToSequenceMasked.gte(SEQUENCE_LOCKTIME_TYPE_FLAG_BN) &&
|
650 | nSequenceMasked.gte(SEQUENCE_LOCKTIME_TYPE_FLAG_BN)))) {
|
651 | return false;
|
652 | }
|
653 |
|
654 |
|
655 |
|
656 | if (nSequenceMasked.gt(txToSequenceMasked)) {
|
657 | return false;
|
658 | }
|
659 | return true;
|
660 | }
|
661 |
|
662 |
|
663 |
|
664 |
|
665 |
|
666 | Interpreter.prototype.step = function() {
|
667 | var fRequireMinimal = (this.flags & Interpreter.SCRIPT_VERIFY_MINIMALDATA) !== 0;
|
668 |
|
669 |
|
670 | var fExec = (this.vfExec.indexOf(false) === -1);
|
671 | var buf, buf1, buf2, spliced, n, x1, x2, bn, bn1, bn2, bufSig, bufPubkey, subscript;
|
672 | var sig, pubkey;
|
673 | var fValue, fSuccess;
|
674 |
|
675 |
|
676 | var chunk = this.script.chunks[this.pc];
|
677 | this.pc++;
|
678 | var opcodenum = chunk.opcodenum;
|
679 | if (_.isUndefined(opcodenum)) {
|
680 | this.errstr = 'SCRIPT_ERR_UNDEFINED_OPCODE';
|
681 | return false;
|
682 | }
|
683 | if (chunk.buf && chunk.buf.length > Interpreter.MAX_SCRIPT_ELEMENT_SIZE) {
|
684 | this.errstr = 'SCRIPT_ERR_PUSH_SIZE';
|
685 | return false;
|
686 | }
|
687 |
|
688 |
|
689 | if (opcodenum > Opcode.OP_16 && ++(this.nOpCount) > 201) {
|
690 | this.errstr = 'SCRIPT_ERR_OP_COUNT';
|
691 | return false;
|
692 | }
|
693 |
|
694 |
|
695 | if (opcodenum === Opcode.OP_CAT ||
|
696 | opcodenum === Opcode.OP_SUBSTR ||
|
697 | opcodenum === Opcode.OP_LEFT ||
|
698 | opcodenum === Opcode.OP_RIGHT ||
|
699 | opcodenum === Opcode.OP_INVERT ||
|
700 | opcodenum === Opcode.OP_AND ||
|
701 | opcodenum === Opcode.OP_OR ||
|
702 | opcodenum === Opcode.OP_XOR ||
|
703 | opcodenum === Opcode.OP_2MUL ||
|
704 | opcodenum === Opcode.OP_2DIV ||
|
705 | opcodenum === Opcode.OP_MUL ||
|
706 | opcodenum === Opcode.OP_DIV ||
|
707 | opcodenum === Opcode.OP_MOD ||
|
708 | opcodenum === Opcode.OP_LSHIFT ||
|
709 | opcodenum === Opcode.OP_RSHIFT) {
|
710 | this.errstr = 'SCRIPT_ERR_DISABLED_OPCODE';
|
711 | return false;
|
712 | }
|
713 |
|
714 | if (fExec && 0 <= opcodenum && opcodenum <= Opcode.OP_PUSHDATA4) {
|
715 | if (fRequireMinimal && !this.script.checkMinimalPush(this.pc - 1)) {
|
716 | this.errstr = 'SCRIPT_ERR_MINIMALDATA';
|
717 | return false;
|
718 | }
|
719 | if (!chunk.buf) {
|
720 | this.stack.push(Interpreter.false);
|
721 | } else if (chunk.len !== chunk.buf.length) {
|
722 | throw new Error('Length of push value not equal to length of data');
|
723 | } else {
|
724 | this.stack.push(chunk.buf);
|
725 | }
|
726 | } else if (fExec || (Opcode.OP_IF <= opcodenum && opcodenum <= Opcode.OP_ENDIF)) {
|
727 | switch (opcodenum) {
|
728 |
|
729 | case Opcode.OP_1NEGATE:
|
730 | case Opcode.OP_1:
|
731 | case Opcode.OP_2:
|
732 | case Opcode.OP_3:
|
733 | case Opcode.OP_4:
|
734 | case Opcode.OP_5:
|
735 | case Opcode.OP_6:
|
736 | case Opcode.OP_7:
|
737 | case Opcode.OP_8:
|
738 | case Opcode.OP_9:
|
739 | case Opcode.OP_10:
|
740 | case Opcode.OP_11:
|
741 | case Opcode.OP_12:
|
742 | case Opcode.OP_13:
|
743 | case Opcode.OP_14:
|
744 | case Opcode.OP_15:
|
745 | case Opcode.OP_16:
|
746 | {
|
747 |
|
748 |
|
749 | n = opcodenum - (Opcode.OP_1 - 1);
|
750 | buf = new BN(n).toScriptNumBuffer();
|
751 | this.stack.push(buf);
|
752 |
|
753 |
|
754 | }
|
755 | break;
|
756 |
|
757 |
|
758 |
|
759 |
|
760 |
|
761 | case Opcode.OP_NOP:
|
762 | break;
|
763 |
|
764 | case Opcode.OP_NOP2:
|
765 | case Opcode.OP_CHECKLOCKTIMEVERIFY:
|
766 |
|
767 | if (!(this.flags & Interpreter.SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY)) {
|
768 |
|
769 | if (this.flags & Interpreter.SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) {
|
770 | this.errstr = 'SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS';
|
771 | return false;
|
772 | }
|
773 | break;
|
774 | }
|
775 |
|
776 | if (this.stack.length < 1) {
|
777 | this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION';
|
778 | return false;
|
779 | }
|
780 |
|
781 |
|
782 |
|
783 |
|
784 |
|
785 |
|
786 |
|
787 |
|
788 |
|
789 |
|
790 |
|
791 |
|
792 |
|
793 |
|
794 |
|
795 | var nLockTime = BN.fromScriptNumBuffer(this.stack[this.stack.length - 1], fRequireMinimal, 5);
|
796 |
|
797 |
|
798 |
|
799 |
|
800 | if (nLockTime.lt(new BN(0))) {
|
801 | this.errstr = 'SCRIPT_ERR_NEGATIVE_LOCKTIME';
|
802 | return false;
|
803 | }
|
804 |
|
805 |
|
806 | if (!this.checkLockTime(nLockTime)) {
|
807 | this.errstr = 'SCRIPT_ERR_UNSATISFIED_LOCKTIME';
|
808 | return false;
|
809 | }
|
810 | break;
|
811 |
|
812 | case Opcode.OP_NOP3:
|
813 | case Opcode.OP_CHECKSEQUENCEVERIFY:
|
814 |
|
815 | if (!(this.flags & Interpreter.SCRIPT_VERIFY_CHECKSEQUENCEVERIFY)) {
|
816 |
|
817 | if (this.flags & Interpreter.SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) {
|
818 | this.errstr = 'SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS';
|
819 | return false;
|
820 | }
|
821 | break;
|
822 | }
|
823 |
|
824 | if (this.stack.length < 1) {
|
825 | this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION';
|
826 | return false;
|
827 | }
|
828 |
|
829 |
|
830 |
|
831 |
|
832 |
|
833 |
|
834 | var nSequence = BN.fromScriptNumBuffer(this.stack[this.stack.length - 1], fRequireMinimal, 5);
|
835 |
|
836 |
|
837 |
|
838 |
|
839 |
|
840 | if (nSequence.lt(new BN(0))) {
|
841 | this.errstr = 'SCRIPT_ERR_NEGATIVE_LOCKTIME';
|
842 | return false;
|
843 | }
|
844 |
|
845 |
|
846 |
|
847 |
|
848 | if ((nSequence &
|
849 | Interpreter.SEQUENCE_LOCKTIME_DISABLE_FLAG) != 0) {
|
850 | break;
|
851 | }
|
852 |
|
853 |
|
854 | if (!this.checkSequence(nSequence)) {
|
855 | this.errstr = 'SCRIPT_ERR_UNSATISFIED_LOCKTIME';
|
856 | return false;
|
857 | }
|
858 | break;
|
859 |
|
860 |
|
861 |
|
862 | case Opcode.OP_NOP1:
|
863 | case Opcode.OP_NOP4:
|
864 | case Opcode.OP_NOP5:
|
865 | case Opcode.OP_NOP6:
|
866 | case Opcode.OP_NOP7:
|
867 | case Opcode.OP_NOP8:
|
868 | case Opcode.OP_NOP9:
|
869 | case Opcode.OP_NOP10:
|
870 | {
|
871 | if (this.flags & Interpreter.SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) {
|
872 | this.errstr = 'SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS';
|
873 | return false;
|
874 | }
|
875 | }
|
876 | break;
|
877 |
|
878 | case Opcode.OP_IF:
|
879 | case Opcode.OP_NOTIF:
|
880 | {
|
881 |
|
882 |
|
883 | fValue = false;
|
884 | if (fExec) {
|
885 | if (this.stack.length < 1) {
|
886 | this.errstr = 'SCRIPT_ERR_UNBALANCED_CONDITIONAL';
|
887 | return false;
|
888 | }
|
889 |
|
890 | buf = this.stack[this.stack.length - 1];
|
891 |
|
892 | if (this.flags & Interpreter.SCRIPT_VERIFY_MINIMALIF) {
|
893 | buf = this.stack[this.stack.length - 1];
|
894 | if (buf.length > 1) {
|
895 | this.errstr = 'SCRIPT_ERR_MINIMALIF';
|
896 | return false;
|
897 | }
|
898 | if (buf.length == 1 && buf[0]!=1) {
|
899 | this.errstr = 'SCRIPT_ERR_MINIMALIF';
|
900 | return false;
|
901 | }
|
902 | }
|
903 | fValue = Interpreter.castToBool(buf);
|
904 | if (opcodenum === Opcode.OP_NOTIF) {
|
905 | fValue = !fValue;
|
906 | }
|
907 | this.stack.pop();
|
908 | }
|
909 | this.vfExec.push(fValue);
|
910 | }
|
911 | break;
|
912 |
|
913 | case Opcode.OP_ELSE:
|
914 | {
|
915 | if (this.vfExec.length === 0) {
|
916 | this.errstr = 'SCRIPT_ERR_UNBALANCED_CONDITIONAL';
|
917 | return false;
|
918 | }
|
919 | this.vfExec[this.vfExec.length - 1] = !this.vfExec[this.vfExec.length - 1];
|
920 | }
|
921 | break;
|
922 |
|
923 | case Opcode.OP_ENDIF:
|
924 | {
|
925 | if (this.vfExec.length === 0) {
|
926 | this.errstr = 'SCRIPT_ERR_UNBALANCED_CONDITIONAL';
|
927 | return false;
|
928 | }
|
929 | this.vfExec.pop();
|
930 | }
|
931 | break;
|
932 |
|
933 | case Opcode.OP_VERIFY:
|
934 | {
|
935 |
|
936 |
|
937 | if (this.stack.length < 1) {
|
938 | this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION';
|
939 | return false;
|
940 | }
|
941 | buf = this.stack[this.stack.length - 1];
|
942 | fValue = Interpreter.castToBool(buf);
|
943 | if (fValue) {
|
944 | this.stack.pop();
|
945 | } else {
|
946 | this.errstr = 'SCRIPT_ERR_VERIFY';
|
947 | return false;
|
948 | }
|
949 | }
|
950 | break;
|
951 |
|
952 | case Opcode.OP_RETURN:
|
953 | {
|
954 | this.errstr = 'SCRIPT_ERR_OP_RETURN';
|
955 | return false;
|
956 | }
|
957 | break;
|
958 |
|
959 |
|
960 |
|
961 |
|
962 |
|
963 | case Opcode.OP_TOALTSTACK:
|
964 | {
|
965 | if (this.stack.length < 1) {
|
966 | this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION';
|
967 | return false;
|
968 | }
|
969 | this.altstack.push(this.stack.pop());
|
970 | }
|
971 | break;
|
972 |
|
973 | case Opcode.OP_FROMALTSTACK:
|
974 | {
|
975 | if (this.altstack.length < 1) {
|
976 | this.errstr = 'SCRIPT_ERR_INVALID_ALTSTACK_OPERATION';
|
977 | return false;
|
978 | }
|
979 | this.stack.push(this.altstack.pop());
|
980 | }
|
981 | break;
|
982 |
|
983 | case Opcode.OP_2DROP:
|
984 | {
|
985 |
|
986 | if (this.stack.length < 2) {
|
987 | this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION';
|
988 | return false;
|
989 | }
|
990 | this.stack.pop();
|
991 | this.stack.pop();
|
992 | }
|
993 | break;
|
994 |
|
995 | case Opcode.OP_2DUP:
|
996 | {
|
997 |
|
998 | if (this.stack.length < 2) {
|
999 | this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION';
|
1000 | return false;
|
1001 | }
|
1002 | buf1 = this.stack[this.stack.length - 2];
|
1003 | buf2 = this.stack[this.stack.length - 1];
|
1004 | this.stack.push(buf1);
|
1005 | this.stack.push(buf2);
|
1006 | }
|
1007 | break;
|
1008 |
|
1009 | case Opcode.OP_3DUP:
|
1010 | {
|
1011 |
|
1012 | if (this.stack.length < 3) {
|
1013 | this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION';
|
1014 | return false;
|
1015 | }
|
1016 | buf1 = this.stack[this.stack.length - 3];
|
1017 | buf2 = this.stack[this.stack.length - 2];
|
1018 | var buf3 = this.stack[this.stack.length - 1];
|
1019 | this.stack.push(buf1);
|
1020 | this.stack.push(buf2);
|
1021 | this.stack.push(buf3);
|
1022 | }
|
1023 | break;
|
1024 |
|
1025 | case Opcode.OP_2OVER:
|
1026 | {
|
1027 |
|
1028 | if (this.stack.length < 4) {
|
1029 | this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION';
|
1030 | return false;
|
1031 | }
|
1032 | buf1 = this.stack[this.stack.length - 4];
|
1033 | buf2 = this.stack[this.stack.length - 3];
|
1034 | this.stack.push(buf1);
|
1035 | this.stack.push(buf2);
|
1036 | }
|
1037 | break;
|
1038 |
|
1039 | case Opcode.OP_2ROT:
|
1040 | {
|
1041 |
|
1042 | if (this.stack.length < 6) {
|
1043 | this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION';
|
1044 | return false;
|
1045 | }
|
1046 | spliced = this.stack.splice(this.stack.length - 6, 2);
|
1047 | this.stack.push(spliced[0]);
|
1048 | this.stack.push(spliced[1]);
|
1049 | }
|
1050 | break;
|
1051 |
|
1052 | case Opcode.OP_2SWAP:
|
1053 | {
|
1054 |
|
1055 | if (this.stack.length < 4) {
|
1056 | this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION';
|
1057 | return false;
|
1058 | }
|
1059 | spliced = this.stack.splice(this.stack.length - 4, 2);
|
1060 | this.stack.push(spliced[0]);
|
1061 | this.stack.push(spliced[1]);
|
1062 | }
|
1063 | break;
|
1064 |
|
1065 | case Opcode.OP_IFDUP:
|
1066 | {
|
1067 |
|
1068 | if (this.stack.length < 1) {
|
1069 | this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION';
|
1070 | return false;
|
1071 | }
|
1072 | buf = this.stack[this.stack.length - 1];
|
1073 | fValue = Interpreter.castToBool(buf);
|
1074 | if (fValue) {
|
1075 | this.stack.push(buf);
|
1076 | }
|
1077 | }
|
1078 | break;
|
1079 |
|
1080 | case Opcode.OP_DEPTH:
|
1081 | {
|
1082 |
|
1083 | buf = new BN(this.stack.length).toScriptNumBuffer();
|
1084 | this.stack.push(buf);
|
1085 | }
|
1086 | break;
|
1087 |
|
1088 | case Opcode.OP_DROP:
|
1089 | {
|
1090 |
|
1091 | if (this.stack.length < 1) {
|
1092 | this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION';
|
1093 | return false;
|
1094 | }
|
1095 | this.stack.pop();
|
1096 | }
|
1097 | break;
|
1098 |
|
1099 | case Opcode.OP_DUP:
|
1100 | {
|
1101 |
|
1102 | if (this.stack.length < 1) {
|
1103 | this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION';
|
1104 | return false;
|
1105 | }
|
1106 | this.stack.push(this.stack[this.stack.length - 1]);
|
1107 | }
|
1108 | break;
|
1109 |
|
1110 | case Opcode.OP_NIP:
|
1111 | {
|
1112 |
|
1113 | if (this.stack.length < 2) {
|
1114 | this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION';
|
1115 | return false;
|
1116 | }
|
1117 | this.stack.splice(this.stack.length - 2, 1);
|
1118 | }
|
1119 | break;
|
1120 |
|
1121 | case Opcode.OP_OVER:
|
1122 | {
|
1123 |
|
1124 | if (this.stack.length < 2) {
|
1125 | this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION';
|
1126 | return false;
|
1127 | }
|
1128 | this.stack.push(this.stack[this.stack.length - 2]);
|
1129 | }
|
1130 | break;
|
1131 |
|
1132 | case Opcode.OP_PICK:
|
1133 | case Opcode.OP_ROLL:
|
1134 | {
|
1135 |
|
1136 |
|
1137 | if (this.stack.length < 2) {
|
1138 | this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION';
|
1139 | return false;
|
1140 | }
|
1141 | buf = this.stack[this.stack.length - 1];
|
1142 | bn = BN.fromScriptNumBuffer(buf, fRequireMinimal);
|
1143 | n = bn.toNumber();
|
1144 | this.stack.pop();
|
1145 | if (n < 0 || n >= this.stack.length) {
|
1146 | this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION';
|
1147 | return false;
|
1148 | }
|
1149 | buf = this.stack[this.stack.length - n - 1];
|
1150 | if (opcodenum === Opcode.OP_ROLL) {
|
1151 | this.stack.splice(this.stack.length - n - 1, 1);
|
1152 | }
|
1153 | this.stack.push(buf);
|
1154 | }
|
1155 | break;
|
1156 |
|
1157 | case Opcode.OP_ROT:
|
1158 | {
|
1159 |
|
1160 |
|
1161 |
|
1162 | if (this.stack.length < 3) {
|
1163 | this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION';
|
1164 | return false;
|
1165 | }
|
1166 | x1 = this.stack[this.stack.length - 3];
|
1167 | x2 = this.stack[this.stack.length - 2];
|
1168 | var x3 = this.stack[this.stack.length - 1];
|
1169 | this.stack[this.stack.length - 3] = x2;
|
1170 | this.stack[this.stack.length - 2] = x3;
|
1171 | this.stack[this.stack.length - 1] = x1;
|
1172 | }
|
1173 | break;
|
1174 |
|
1175 | case Opcode.OP_SWAP:
|
1176 | {
|
1177 |
|
1178 | if (this.stack.length < 2) {
|
1179 | this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION';
|
1180 | return false;
|
1181 | }
|
1182 | x1 = this.stack[this.stack.length - 2];
|
1183 | x2 = this.stack[this.stack.length - 1];
|
1184 | this.stack[this.stack.length - 2] = x2;
|
1185 | this.stack[this.stack.length - 1] = x1;
|
1186 | }
|
1187 | break;
|
1188 |
|
1189 | case Opcode.OP_TUCK:
|
1190 | {
|
1191 |
|
1192 | if (this.stack.length < 2) {
|
1193 | this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION';
|
1194 | return false;
|
1195 | }
|
1196 | this.stack.splice(this.stack.length - 2, 0, this.stack[this.stack.length - 1]);
|
1197 | }
|
1198 | break;
|
1199 |
|
1200 |
|
1201 | case Opcode.OP_SIZE:
|
1202 | {
|
1203 |
|
1204 | if (this.stack.length < 1) {
|
1205 | this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION';
|
1206 | return false;
|
1207 | }
|
1208 | bn = new BN(this.stack[this.stack.length - 1].length);
|
1209 | this.stack.push(bn.toScriptNumBuffer());
|
1210 | }
|
1211 | break;
|
1212 |
|
1213 |
|
1214 |
|
1215 |
|
1216 |
|
1217 | case Opcode.OP_EQUAL:
|
1218 | case Opcode.OP_EQUALVERIFY:
|
1219 |
|
1220 | {
|
1221 |
|
1222 | if (this.stack.length < 2) {
|
1223 | this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION';
|
1224 | return false;
|
1225 | }
|
1226 | buf1 = this.stack[this.stack.length - 2];
|
1227 | buf2 = this.stack[this.stack.length - 1];
|
1228 | var fEqual = buf1.toString('hex') === buf2.toString('hex');
|
1229 | this.stack.pop();
|
1230 | this.stack.pop();
|
1231 | this.stack.push(fEqual ? Interpreter.true : Interpreter.false);
|
1232 | if (opcodenum === Opcode.OP_EQUALVERIFY) {
|
1233 | if (fEqual) {
|
1234 | this.stack.pop();
|
1235 | } else {
|
1236 | this.errstr = 'SCRIPT_ERR_EQUALVERIFY';
|
1237 | return false;
|
1238 | }
|
1239 | }
|
1240 | }
|
1241 | break;
|
1242 |
|
1243 |
|
1244 |
|
1245 |
|
1246 |
|
1247 | case Opcode.OP_1ADD:
|
1248 | case Opcode.OP_1SUB:
|
1249 | case Opcode.OP_NEGATE:
|
1250 | case Opcode.OP_ABS:
|
1251 | case Opcode.OP_NOT:
|
1252 | case Opcode.OP_0NOTEQUAL:
|
1253 | {
|
1254 |
|
1255 | if (this.stack.length < 1) {
|
1256 | this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION';
|
1257 | return false;
|
1258 | }
|
1259 | buf = this.stack[this.stack.length - 1];
|
1260 | bn = BN.fromScriptNumBuffer(buf, fRequireMinimal);
|
1261 | switch (opcodenum) {
|
1262 | case Opcode.OP_1ADD:
|
1263 | bn = bn.add(BN.One);
|
1264 | break;
|
1265 | case Opcode.OP_1SUB:
|
1266 | bn = bn.sub(BN.One);
|
1267 | break;
|
1268 | case Opcode.OP_NEGATE:
|
1269 | bn = bn.neg();
|
1270 | break;
|
1271 | case Opcode.OP_ABS:
|
1272 | if (bn.cmp(BN.Zero) < 0) {
|
1273 | bn = bn.neg();
|
1274 | }
|
1275 | break;
|
1276 | case Opcode.OP_NOT:
|
1277 | bn = new BN((bn.cmp(BN.Zero) === 0) + 0);
|
1278 | break;
|
1279 | case Opcode.OP_0NOTEQUAL:
|
1280 | bn = new BN((bn.cmp(BN.Zero) !== 0) + 0);
|
1281 | break;
|
1282 |
|
1283 | }
|
1284 | this.stack.pop();
|
1285 | this.stack.push(bn.toScriptNumBuffer());
|
1286 | }
|
1287 | break;
|
1288 |
|
1289 | case Opcode.OP_ADD:
|
1290 | case Opcode.OP_SUB:
|
1291 | case Opcode.OP_BOOLAND:
|
1292 | case Opcode.OP_BOOLOR:
|
1293 | case Opcode.OP_NUMEQUAL:
|
1294 | case Opcode.OP_NUMEQUALVERIFY:
|
1295 | case Opcode.OP_NUMNOTEQUAL:
|
1296 | case Opcode.OP_LESSTHAN:
|
1297 | case Opcode.OP_GREATERTHAN:
|
1298 | case Opcode.OP_LESSTHANOREQUAL:
|
1299 | case Opcode.OP_GREATERTHANOREQUAL:
|
1300 | case Opcode.OP_MIN:
|
1301 | case Opcode.OP_MAX:
|
1302 | {
|
1303 |
|
1304 | if (this.stack.length < 2) {
|
1305 | this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION';
|
1306 | return false;
|
1307 | }
|
1308 | bn1 = BN.fromScriptNumBuffer(this.stack[this.stack.length - 2], fRequireMinimal);
|
1309 | bn2 = BN.fromScriptNumBuffer(this.stack[this.stack.length - 1], fRequireMinimal);
|
1310 | bn = new BN(0);
|
1311 |
|
1312 | switch (opcodenum) {
|
1313 | case Opcode.OP_ADD:
|
1314 | bn = bn1.add(bn2);
|
1315 | break;
|
1316 |
|
1317 | case Opcode.OP_SUB:
|
1318 | bn = bn1.sub(bn2);
|
1319 | break;
|
1320 |
|
1321 |
|
1322 | case Opcode.OP_BOOLAND:
|
1323 | bn = new BN(((bn1.cmp(BN.Zero) !== 0) && (bn2.cmp(BN.Zero) !== 0)) + 0);
|
1324 | break;
|
1325 |
|
1326 | case Opcode.OP_BOOLOR:
|
1327 | bn = new BN(((bn1.cmp(BN.Zero) !== 0) || (bn2.cmp(BN.Zero) !== 0)) + 0);
|
1328 | break;
|
1329 |
|
1330 | case Opcode.OP_NUMEQUAL:
|
1331 | bn = new BN((bn1.cmp(bn2) === 0) + 0);
|
1332 | break;
|
1333 |
|
1334 | case Opcode.OP_NUMEQUALVERIFY:
|
1335 | bn = new BN((bn1.cmp(bn2) === 0) + 0);
|
1336 | break;
|
1337 |
|
1338 | case Opcode.OP_NUMNOTEQUAL:
|
1339 | bn = new BN((bn1.cmp(bn2) !== 0) + 0);
|
1340 | break;
|
1341 |
|
1342 | case Opcode.OP_LESSTHAN:
|
1343 | bn = new BN((bn1.cmp(bn2) < 0) + 0);
|
1344 | break;
|
1345 |
|
1346 | case Opcode.OP_GREATERTHAN:
|
1347 | bn = new BN((bn1.cmp(bn2) > 0) + 0);
|
1348 | break;
|
1349 |
|
1350 | case Opcode.OP_LESSTHANOREQUAL:
|
1351 | bn = new BN((bn1.cmp(bn2) <= 0) + 0);
|
1352 | break;
|
1353 |
|
1354 | case Opcode.OP_GREATERTHANOREQUAL:
|
1355 | bn = new BN((bn1.cmp(bn2) >= 0) + 0);
|
1356 | break;
|
1357 | case Opcode.OP_MIN:
|
1358 | bn = (bn1.cmp(bn2) < 0 ? bn1 : bn2);
|
1359 | break;
|
1360 | case Opcode.OP_MAX:
|
1361 | bn = (bn1.cmp(bn2) > 0 ? bn1 : bn2);
|
1362 | break;
|
1363 |
|
1364 | }
|
1365 | this.stack.pop();
|
1366 | this.stack.pop();
|
1367 | this.stack.push(bn.toScriptNumBuffer());
|
1368 |
|
1369 | if (opcodenum === Opcode.OP_NUMEQUALVERIFY) {
|
1370 |
|
1371 | if (Interpreter.castToBool(this.stack[this.stack.length - 1])) {
|
1372 | this.stack.pop();
|
1373 | } else {
|
1374 | this.errstr = 'SCRIPT_ERR_NUMEQUALVERIFY';
|
1375 | return false;
|
1376 | }
|
1377 | }
|
1378 | }
|
1379 | break;
|
1380 |
|
1381 | case Opcode.OP_WITHIN:
|
1382 | {
|
1383 |
|
1384 | if (this.stack.length < 3) {
|
1385 | this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION';
|
1386 | return false;
|
1387 | }
|
1388 | bn1 = BN.fromScriptNumBuffer(this.stack[this.stack.length - 3], fRequireMinimal);
|
1389 | bn2 = BN.fromScriptNumBuffer(this.stack[this.stack.length - 2], fRequireMinimal);
|
1390 | var bn3 = BN.fromScriptNumBuffer(this.stack[this.stack.length - 1], fRequireMinimal);
|
1391 |
|
1392 | fValue = (bn2.cmp(bn1) <= 0) && (bn1.cmp(bn3) < 0);
|
1393 | this.stack.pop();
|
1394 | this.stack.pop();
|
1395 | this.stack.pop();
|
1396 | this.stack.push(fValue ? Interpreter.true : Interpreter.false);
|
1397 | }
|
1398 | break;
|
1399 |
|
1400 |
|
1401 |
|
1402 |
|
1403 |
|
1404 | case Opcode.OP_RIPEMD160:
|
1405 | case Opcode.OP_SHA1:
|
1406 | case Opcode.OP_SHA256:
|
1407 | case Opcode.OP_HASH160:
|
1408 | case Opcode.OP_HASH256:
|
1409 | {
|
1410 |
|
1411 | if (this.stack.length < 1) {
|
1412 | this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION';
|
1413 | return false;
|
1414 | }
|
1415 | buf = this.stack[this.stack.length - 1];
|
1416 |
|
1417 |
|
1418 | var bufHash;
|
1419 | if (opcodenum === Opcode.OP_RIPEMD160) {
|
1420 | bufHash = Hash.ripemd160(buf);
|
1421 | } else if (opcodenum === Opcode.OP_SHA1) {
|
1422 | bufHash = Hash.sha1(buf);
|
1423 | } else if (opcodenum === Opcode.OP_SHA256) {
|
1424 | bufHash = Hash.sha256(buf);
|
1425 | } else if (opcodenum === Opcode.OP_HASH160) {
|
1426 | bufHash = Hash.sha256ripemd160(buf);
|
1427 | } else if (opcodenum === Opcode.OP_HASH256) {
|
1428 | bufHash = Hash.sha256sha256(buf);
|
1429 | }
|
1430 | this.stack.pop();
|
1431 | this.stack.push(bufHash);
|
1432 | }
|
1433 | break;
|
1434 |
|
1435 | case Opcode.OP_CODESEPARATOR:
|
1436 | {
|
1437 |
|
1438 | this.pbegincodehash = this.pc;
|
1439 | }
|
1440 | break;
|
1441 |
|
1442 | case Opcode.OP_CHECKSIG:
|
1443 | case Opcode.OP_CHECKSIGVERIFY:
|
1444 | {
|
1445 |
|
1446 | if (this.stack.length < 2) {
|
1447 | this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION';
|
1448 | return false;
|
1449 | }
|
1450 |
|
1451 | bufSig = this.stack[this.stack.length - 2];
|
1452 | bufPubkey = this.stack[this.stack.length - 1];
|
1453 | if (!this.checkSignatureEncoding(bufSig) || !this.checkPubkeyEncoding(bufPubkey)) {
|
1454 | return false;
|
1455 | }
|
1456 |
|
1457 |
|
1458 |
|
1459 | subscript = new Script().set({
|
1460 | chunks: this.script.chunks.slice(this.pbegincodehash)
|
1461 | });
|
1462 |
|
1463 |
|
1464 | var tmpScript = new Script().add(bufSig);
|
1465 | subscript.findAndDelete(tmpScript);
|
1466 |
|
1467 | try {
|
1468 | sig = Signature.fromTxFormat(bufSig);
|
1469 | pubkey = PublicKey.fromBuffer(bufPubkey, false);
|
1470 | fSuccess = this.tx.verifySignature(sig, pubkey, this.nin, subscript, this.sigversion, this.satoshis);
|
1471 | } catch (e) {
|
1472 |
|
1473 | fSuccess = false;
|
1474 | }
|
1475 |
|
1476 | if (!fSuccess && (this.flags & Interpreter.SCRIPT_VERIFY_NULLFAIL) &&
|
1477 | bufSig.length) {
|
1478 | this.errstr = 'SCRIPT_ERR_NULLFAIL';
|
1479 | return false;
|
1480 | }
|
1481 |
|
1482 | this.stack.pop();
|
1483 | this.stack.pop();
|
1484 |
|
1485 |
|
1486 | this.stack.push(fSuccess ? Interpreter.true : Interpreter.false);
|
1487 | if (opcodenum === Opcode.OP_CHECKSIGVERIFY) {
|
1488 | if (fSuccess) {
|
1489 | this.stack.pop();
|
1490 | } else {
|
1491 | this.errstr = 'SCRIPT_ERR_CHECKSIGVERIFY';
|
1492 | return false;
|
1493 | }
|
1494 | }
|
1495 | }
|
1496 | break;
|
1497 |
|
1498 | case Opcode.OP_CHECKMULTISIG:
|
1499 | case Opcode.OP_CHECKMULTISIGVERIFY:
|
1500 | {
|
1501 |
|
1502 |
|
1503 | var i = 1;
|
1504 | if (this.stack.length < i) {
|
1505 | this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION';
|
1506 | return false;
|
1507 | }
|
1508 |
|
1509 | var nKeysCount = BN.fromScriptNumBuffer(this.stack[this.stack.length - i], fRequireMinimal).toNumber();
|
1510 | if (nKeysCount < 0 || nKeysCount > 20) {
|
1511 | this.errstr = 'SCRIPT_ERR_PUBKEY_COUNT';
|
1512 | return false;
|
1513 | }
|
1514 | this.nOpCount += nKeysCount;
|
1515 | if (this.nOpCount > 201) {
|
1516 | this.errstr = 'SCRIPT_ERR_OP_COUNT';
|
1517 | return false;
|
1518 | }
|
1519 |
|
1520 | var ikey = ++i;
|
1521 | i += nKeysCount;
|
1522 |
|
1523 |
|
1524 |
|
1525 |
|
1526 |
|
1527 | var ikey2 = nKeysCount + 2;
|
1528 |
|
1529 | if (this.stack.length < i) {
|
1530 | this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION';
|
1531 | return false;
|
1532 | }
|
1533 |
|
1534 | var nSigsCount = BN.fromScriptNumBuffer(this.stack[this.stack.length - i], fRequireMinimal).toNumber();
|
1535 | if (nSigsCount < 0 || nSigsCount > nKeysCount) {
|
1536 | this.errstr = 'SCRIPT_ERR_SIG_COUNT';
|
1537 | return false;
|
1538 | }
|
1539 |
|
1540 | var isig = ++i;
|
1541 | i += nSigsCount;
|
1542 | if (this.stack.length < i) {
|
1543 | this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION';
|
1544 | return false;
|
1545 | }
|
1546 |
|
1547 |
|
1548 | subscript = new Script().set({
|
1549 | chunks: this.script.chunks.slice(this.pbegincodehash)
|
1550 | });
|
1551 |
|
1552 |
|
1553 | for (var k = 0; k < nSigsCount; k++) {
|
1554 | bufSig = this.stack[this.stack.length - isig - k];
|
1555 | subscript.findAndDelete(new Script().add(bufSig));
|
1556 | }
|
1557 |
|
1558 | fSuccess = true;
|
1559 | while (fSuccess && nSigsCount > 0) {
|
1560 |
|
1561 | bufSig = this.stack[this.stack.length - isig];
|
1562 |
|
1563 | bufPubkey = this.stack[this.stack.length - ikey];
|
1564 |
|
1565 | if (!this.checkSignatureEncoding(bufSig) || !this.checkPubkeyEncoding(bufPubkey)) {
|
1566 | return false;
|
1567 | }
|
1568 |
|
1569 | var fOk;
|
1570 | try {
|
1571 | sig = Signature.fromTxFormat(bufSig);
|
1572 | pubkey = PublicKey.fromBuffer(bufPubkey, false);
|
1573 | fOk = this.tx.verifySignature(sig, pubkey, this.nin, subscript, this.sigversion, this.satoshis);
|
1574 | } catch (e) {
|
1575 |
|
1576 | fOk = false;
|
1577 | }
|
1578 |
|
1579 | if (fOk) {
|
1580 | isig++;
|
1581 | nSigsCount--;
|
1582 | }
|
1583 | ikey++;
|
1584 | nKeysCount--;
|
1585 |
|
1586 |
|
1587 |
|
1588 | if (nSigsCount > nKeysCount) {
|
1589 | fSuccess = false;
|
1590 | }
|
1591 | }
|
1592 |
|
1593 |
|
1594 |
|
1595 | while (i-- > 1) {
|
1596 | if (!fSuccess && (this.flags & Interpreter.SCRIPT_VERIFY_NULLFAIL) &&
|
1597 | !ikey2 && this.stack[this.stack.length - 1].length) {
|
1598 |
|
1599 | this.errstr = 'SCRIPT_ERR_NULLFAIL';
|
1600 | return false;
|
1601 | }
|
1602 |
|
1603 | if (ikey2 > 0) {
|
1604 | ikey2--;
|
1605 | }
|
1606 |
|
1607 | this.stack.pop();
|
1608 | }
|
1609 |
|
1610 |
|
1611 |
|
1612 |
|
1613 |
|
1614 |
|
1615 |
|
1616 | if (this.stack.length < 1) {
|
1617 | this.errstr = 'SCRIPT_ERR_INVALID_STACK_OPERATION';
|
1618 | return false;
|
1619 | }
|
1620 | if ((this.flags & Interpreter.SCRIPT_VERIFY_NULLDUMMY) && this.stack[this.stack.length - 1].length) {
|
1621 | this.errstr = 'SCRIPT_ERR_SIG_NULLDUMMY';
|
1622 | return false;
|
1623 | }
|
1624 | this.stack.pop();
|
1625 |
|
1626 | this.stack.push(fSuccess ? Interpreter.true : Interpreter.false);
|
1627 |
|
1628 | if (opcodenum === Opcode.OP_CHECKMULTISIGVERIFY) {
|
1629 | if (fSuccess) {
|
1630 | this.stack.pop();
|
1631 | } else {
|
1632 | this.errstr = 'SCRIPT_ERR_CHECKMULTISIGVERIFY';
|
1633 | return false;
|
1634 | }
|
1635 | }
|
1636 | }
|
1637 | break;
|
1638 |
|
1639 | default:
|
1640 | this.errstr = 'SCRIPT_ERR_BAD_OPCODE';
|
1641 | return false;
|
1642 | }
|
1643 | }
|
1644 |
|
1645 | return true;
|
1646 | };
|
1647 |
|