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