Completed
Push — master ( 7a567c...8c5683 )
by thomas
19:10 queued 04:46
created

Interpreter::verifyWitnessProgram()   C

Complexity

Conditions 12
Paths 22

Size

Total Lines 57
Code Lines 33

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 31
CRAP Score 12.0988

Importance

Changes 0
Metric Value
cc 12
eloc 33
c 0
b 0
f 0
nc 22
nop 4
dl 0
loc 57
ccs 31
cts 34
cp 0.9118
crap 12.0988
rs 6.62

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace BitWasp\Bitcoin\Script\Interpreter;
4
5
use BitWasp\Bitcoin\Crypto\EcAdapter\Adapter\EcAdapterInterface;
6
use BitWasp\Bitcoin\Crypto\Hash;
7
use BitWasp\Bitcoin\Exceptions\SignatureNotCanonical;
8
use BitWasp\Bitcoin\Exceptions\ScriptRuntimeException;
9
use BitWasp\Bitcoin\Script\Classifier\OutputClassifier;
10
use BitWasp\Bitcoin\Script\Opcodes;
11
use BitWasp\Bitcoin\Script\Script;
12
use BitWasp\Bitcoin\Script\ScriptFactory;
13
use BitWasp\Bitcoin\Script\ScriptInterface;
14
use BitWasp\Bitcoin\Script\ScriptWitness;
15
use BitWasp\Bitcoin\Script\ScriptWitnessInterface;
16
use BitWasp\Bitcoin\Script\WitnessProgram;
17
use BitWasp\Bitcoin\Signature\TransactionSignature;
18
use BitWasp\Bitcoin\Transaction\TransactionInputInterface;
19
use BitWasp\Buffertools\Buffer;
20
use BitWasp\Buffertools\BufferInterface;
21
22
class Interpreter implements InterpreterInterface
23
{
24
25
    /**
26
     * @var \BitWasp\Bitcoin\Math\Math
27
     */
28
    private $math;
29
30
    /**
31
     * @var BufferInterface
32
     */
33
    private $vchFalse;
34
35
    /**
36
     * @var BufferInterface
37
     */
38
    private $vchTrue;
39
40
    /**
41
     * @var array
42
     */
43
    private $disabledOps = [
44
        Opcodes::OP_CAT,    Opcodes::OP_SUBSTR, Opcodes::OP_LEFT,  Opcodes::OP_RIGHT,
45
        Opcodes::OP_INVERT, Opcodes::OP_AND,    Opcodes::OP_OR,    Opcodes::OP_XOR,
46
        Opcodes::OP_2MUL,   Opcodes::OP_2DIV,   Opcodes::OP_MUL,   Opcodes::OP_DIV,
47
        Opcodes::OP_MOD,    Opcodes::OP_LSHIFT, Opcodes::OP_RSHIFT
48
    ];
49
50
    /**
51
     * @param EcAdapterInterface $ecAdapter
52
     */
53 63
    public function __construct(EcAdapterInterface $ecAdapter)
54
    {
55 63
        $this->math = $ecAdapter->getMath();
56 63
        $this->vchFalse = new Buffer("", 0, $this->math);
57 63
        $this->vchTrue = new Buffer("\x01", 1, $this->math);
58 63
    }
59
60
    /**
61
     * Cast the value to a boolean
62
     *
63
     * @param BufferInterface $value
64
     * @return bool
65
     */
66 852
    public function castToBool(BufferInterface $value)
67
    {
68 852
        $val = $value->getBinary();
69 852
        for ($i = 0, $size = strlen($val); $i < $size; $i++) {
70 781
            $chr = ord($val[$i]);
71 781
            if ($chr != 0) {
72 778
                if (($i == ($size - 1)) && $chr == 0x80) {
73
                    return false;
74
                }
75 778
                return true;
76
            }
77 2
        }
78 202
        return false;
79
    }
80
81
    /**
82
     * @param BufferInterface $signature
83
     * @return bool
84
     */
85
    public function isValidSignatureEncoding(BufferInterface $signature)
86
    {
87
        try {
88
            TransactionSignature::isDERSignature($signature);
89
            return true;
90
        } catch (SignatureNotCanonical $e) {
91
            /* In any case, we will return false outside this block */
92
        }
93
94
        return false;
95
    }
96
97
    /**
98
     * @param int $opCode
99
     * @param BufferInterface $pushData
100
     * @return bool
101
     * @throws \Exception
102
     */
103 118
    public function checkMinimalPush($opCode, BufferInterface $pushData)
104
    {
105 118
        $pushSize = $pushData->getSize();
106 118
        $binary = $pushData->getBinary();
107
108 118
        if ($pushSize === 0) {
109 57
            return $opCode === Opcodes::OP_0;
110 97
        } elseif ($pushSize === 1) {
111 25
            $first = ord($binary[0]);
112
113 25
            if ($first >= 1 && $first <= 16) {
114 19
                return $opCode === (Opcodes::OP_1 + ($first - 1));
115 9
            } elseif ($first === 0x81) {
116 9
                return $opCode === Opcodes::OP_1NEGATE;
117
            }
118 75
        } elseif ($pushSize <= 75) {
119 73
            return $opCode === $pushSize;
120 5
        } elseif ($pushSize <= 255) {
121 4
            return $opCode === Opcodes::OP_PUSHDATA1;
122 4
        } elseif ($pushSize <= 65535) {
123 4
            return $opCode === Opcodes::OP_PUSHDATA2;
124
        }
125
126 8
        return true;
127
    }
128
129
    /**
130
     * @param int $count
131
     * @return $this
132
     */
133 1123
    private function checkOpcodeCount($count)
134
    {
135 1123
        if ($count > 201) {
136 5
            throw new \RuntimeException('Error: Script op code count');
137
        }
138
139 1123
        return $this;
140
    }
141
142
    /**
143
     * @param WitnessProgram $witnessProgram
144
     * @param ScriptWitnessInterface $scriptWitness
145
     * @param int $flags
146
     * @param Checker $checker
147
     * @return bool
148
     */
149 34
    private function verifyWitnessProgram(WitnessProgram $witnessProgram, ScriptWitnessInterface $scriptWitness, $flags, Checker $checker)
150
    {
151 34
        $witnessCount = count($scriptWitness);
152
153 34
        if ($witnessProgram->getVersion() == 0) {
154 33
            $buffer = $witnessProgram->getProgram();
155 33
            if ($buffer->getSize() === 32) {
156
                // Version 0 segregated witness program: SHA256(Script) in program, Script + inputs in witness
157 19
                if ($witnessCount === 0) {
158
                    // Must contain script at least
159 1
                    return false;
160
                }
161
162 18
                $scriptPubKey = new Script($scriptWitness[$witnessCount - 1]);
163 18
                $stackValues = $scriptWitness->slice(0, -1);
164 18
                $hashScriptPubKey = Hash::sha256($scriptPubKey->getBuffer());
165
166 18
                if (!$hashScriptPubKey->equals($buffer)) {
167 12
                    return false;
168 2
                }
169 20
            } elseif ($buffer->getSize() === 20) {
170
                // Version 0 special case for pay-to-pubkeyhash
171 13
                if ($witnessCount !== 2) {
172
                    // 2 items in witness - <signature> <pubkey>
173 1
                    return false;
174
                }
175
176 12
                $scriptPubKey = ScriptFactory::create()->sequence([Opcodes::OP_DUP, Opcodes::OP_HASH160, $buffer, Opcodes::OP_EQUALVERIFY, Opcodes::OP_CHECKSIG])->getScript();
177 12
                $stackValues = $scriptWitness;
178 4
            } else {
179 19
                return false;
180
            }
181 11
        } elseif ($flags & self::VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM) {
182 1
            return false;
183
        } else {
184
            return false;
185
        }
186
187 28
        $mainStack = new Stack();
188 28
        foreach ($stackValues as $value) {
189 27
            $mainStack->push($value);
190 10
        }
191
192 28
        if (!$this->evaluate($scriptPubKey, $mainStack, 1, $flags, $checker)) {
193
            return false;
194
        }
195
196 28
        if ($mainStack->count() !== 1) {
197
            return false;
198
        }
199
200 28
        if (!$this->castToBool($mainStack->bottom())) {
201 9
            return false;
202
        }
203
204 19
        return true;
205
    }
206
207
    /**
208
     * @param ScriptInterface $scriptSig
209
     * @param ScriptInterface $scriptPubKey
210
     * @param int $flags
211
     * @param Checker $checker
212
     * @param ScriptWitnessInterface|null $witness
213
     * @return bool
214
     */
215 1193
    public function verify(ScriptInterface $scriptSig, ScriptInterface $scriptPubKey, $flags, Checker $checker, ScriptWitnessInterface $witness = null)
216
    {
217 1193
        static $emptyWitness = null;
218 1193
        if ($emptyWitness === null) {
219 3
            $emptyWitness = new ScriptWitness([]);
220 2
        }
221
222 1193
        $witness = is_null($witness) ? $emptyWitness : $witness;
223
224 1193
        if (($flags & self::VERIFY_SIGPUSHONLY) != 0 && !$scriptSig->isPushOnly()) {
225 2
            return false;
226
        }
227
228 1191
        $stack = new Stack();
229 1191
        if (!$this->evaluate($scriptSig, $stack, 0, $flags, $checker)) {
230 58
            return false;
231
        }
232
233 1133
        $backup = [];
234 1133
        if ($flags & self::VERIFY_P2SH) {
235 803
            foreach ($stack as $s) {
236 648
                $backup[] = $s;
237 30
            }
238 30
        }
239
240 1133
        if (!$this->evaluate($scriptPubKey, $stack, 0, $flags, $checker)) {
241 381
            return false;
242
        }
243
244 752
        if ($stack->isEmpty()) {
245 13
            return false;
246
        }
247
248 739
        if (false === $this->castToBool($stack[-1])) {
249 53
            return false;
250
        }
251
252 686
        $program = null;
253 686
        if ($flags & self::VERIFY_WITNESS) {
254 58
            if ($scriptPubKey->isWitness($program)) {
255
                /** @var WitnessProgram $program */
256 23
                if ($scriptSig->getBuffer()->getSize() !== 0) {
257 1
                    return false;
258
                }
259
260 22
                if (!$this->verifyWitnessProgram($program, $witness, $flags, $checker)) {
261 11
                    return false;
262
                }
263
264 11
                $stack->resize(1);
265 6
            }
266 24
        }
267
268 674
        if ($flags & self::VERIFY_P2SH && (new OutputClassifier())->isPayToScriptHash($scriptPubKey)) {
269 43
            if (!$scriptSig->isPushOnly()) {
270 6
                return false;
271
            }
272
273 37
            $stack = new Stack();
274 37
            foreach ($backup as $i) {
275 37
                $stack->push($i);
276 10
            }
277
278
            // Restore mainStack to how it was after evaluating scriptSig
279 37
            if ($stack->isEmpty()) {
280
                return false;
281
            }
282
283
            // Load redeemscript as the scriptPubKey
284 37
            $scriptPubKey = new Script($stack->bottom());
285 37
            $stack->pop();
286
287 37
            if (!$this->evaluate($scriptPubKey, $stack, 0, $flags, $checker)) {
288 7
                return false;
289
            }
290
291 30
            if ($stack->isEmpty()) {
292
                return false;
293
            }
294
295 30
            if (!$this->castToBool($stack->bottom())) {
296 1
                return false;
297
            }
298
299 29
            if ($flags & self::VERIFY_WITNESS) {
300 19
                if ($scriptPubKey->isWitness($program)) {
301
                    /** @var WitnessProgram $program */
302 13
                    if ($scriptSig != (ScriptFactory::create()->push($scriptPubKey->getBuffer())->getScript())) {
303 1
                        return false; // SCRIPT_ERR_WITNESS_MALLEATED_P2SH
304
                    }
305
306 12
                    if (!$this->verifyWitnessProgram($program, $witness, $flags, $checker)) {
307 4
                        return false;
308
                    }
309
310 8
                    $stack->resize(1);
311 4
                }
312 8
            }
313 8
        }
314
315 655
        if ($flags & self::VERIFY_CLEAN_STACK) {
316 12
            if (!($flags & self::VERIFY_P2SH != 0) && ($flags & self::VERIFY_WITNESS != 0)) {
317
                return false; // implied flags required
318
            }
319
320 12
            if (count($stack) != 1) {
321 2
                return false; // Cleanstack
322
            }
323 6
        }
324
325 653
        if ($flags & self::VERIFY_WITNESS) {
326 41
            if (!$flags & self::VERIFY_P2SH) {
327
                return false; //
328
            }
329
330 41
            if ($program === null && !$witness->isNull()) {
331 1
                return false; // SCRIPT_ERR_WITNESS_UNEXPECTED
332
            }
333 24
        }
334
335 652
        return true;
336
    }
337
338
    /**
339
     * @param Stack $vfStack
340
     * @param bool $value
341
     * @return bool
342
     */
343 1187
    private function checkExec(Stack $vfStack, $value)
344
    {
345 1187
        $ret = 0;
346 1187
        foreach ($vfStack as $item) {
347 242
            if ($item == $value) {
348 242
                $ret++;
349
            }
350 90
        }
351
352 1187
        return $ret;
353
    }
354
355
    /**
356
     * @param ScriptInterface $script
357
     * @param Stack $mainStack
358
     * @param int $sigVersion
359
     * @param int $flags
360
     * @param Checker $checker
361
     * @return bool
362
     */
363 1194
    public function evaluate(ScriptInterface $script, Stack $mainStack, $sigVersion, $flags, Checker $checker)
364
    {
365 1194
        $hashStartPos = 0;
366 1194
        $opCount = 0;
367 1194
        $altStack = new Stack();
368 1194
        $vfStack = new Stack();
369 1194
        $minimal = ($flags & self::VERIFY_MINIMALDATA) != 0;
370 1194
        $parser = $script->getScriptParser();
371
372 1194
        if ($script->getBuffer()->getSize() > 10000) {
373 1
            return false;
374
        }
375
376
        try {
377 1194
            foreach ($parser as $operation) {
378 1187
                $opCode = $operation->getOp();
379 1187
                $pushData = $operation->getData();
380 1187
                $fExec = !$this->checkExec($vfStack, false);
381
382
                // If pushdata was written to
383 1187
                if ($operation->isPush() && $operation->getDataSize() > InterpreterInterface::MAX_SCRIPT_ELEMENT_SIZE) {
384 5
                    throw new \RuntimeException('Error - push size');
385
                }
386
387
                // OP_RESERVED should not count towards opCount
388 1184
                if ($opCode > Opcodes::OP_16 && ++$opCount) {
389 1123
                    $this->checkOpcodeCount($opCount);
390 86
                }
391
392 1184
                if (in_array($opCode, $this->disabledOps, true)) {
393 24
                    throw new \RuntimeException('Disabled Opcode');
394
                }
395
396 1184
                if ($fExec && $operation->isPush()) {
397
                    // In range of a pushdata opcode
398 884
                    if ($minimal && !$this->checkMinimalPush($opCode, $pushData)) {
399 21
                        throw new ScriptRuntimeException(self::VERIFY_MINIMALDATA, 'Minimal pushdata required');
400
                    }
401
402 863
                    $mainStack->push($pushData);
403
                    // echo " - [pushed '" . $pushData->getHex() . "']\n";
404 1148
                } elseif ($fExec || (Opcodes::OP_IF <= $opCode && $opCode <= Opcodes::OP_ENDIF)) {
405
                    // echo "OPCODE - " . $script->getOpcodes()->getOp($opCode) . "\n";
406
                    switch ($opCode) {
407 1146
                        case Opcodes::OP_1NEGATE:
408 1146
                        case Opcodes::OP_1:
409 1124
                        case Opcodes::OP_2:
410 1120
                        case Opcodes::OP_3:
411 1120
                        case Opcodes::OP_4:
412 1120
                        case Opcodes::OP_5:
413 1120
                        case Opcodes::OP_6:
414 1120
                        case Opcodes::OP_7:
415 1119
                        case Opcodes::OP_8:
416 1119
                        case Opcodes::OP_9:
417 1119
                        case Opcodes::OP_10:
418 1119
                        case Opcodes::OP_11:
419 1118
                        case Opcodes::OP_12:
420 1118
                        case Opcodes::OP_13:
421 1118
                        case Opcodes::OP_14:
422 1118
                        case Opcodes::OP_15:
423 1118
                        case Opcodes::OP_16:
424 687
                            $num = \BitWasp\Bitcoin\Script\decodeOpN($opCode);
425 687
                            $mainStack->push(Number::int($num)->getBuffer());
426 687
                            break;
427
428 1118
                        case Opcodes::OP_CHECKLOCKTIMEVERIFY:
429 6
                            if (!($flags & self::VERIFY_CHECKLOCKTIMEVERIFY)) {
430 6
                                if ($flags & self::VERIFY_DISCOURAGE_UPGRADABLE_NOPS) {
431 1
                                    throw new ScriptRuntimeException(self::VERIFY_DISCOURAGE_UPGRADABLE_NOPS, 'Upgradable NOP found - this is discouraged');
432
                                }
433 5
                                break;
434
                            }
435
436
                            if ($mainStack->isEmpty()) {
437
                                throw new \RuntimeException('Invalid stack operation - CLTV');
438
                            }
439
440
                            $lockTime = Number::buffer($mainStack[-1], $minimal, 5, $this->math);
441
                            if (!$checker->checkLockTime($lockTime)) {
442
                                throw new ScriptRuntimeException(self::VERIFY_CHECKLOCKTIMEVERIFY, 'Unsatisfied locktime');
443
                            }
444
445
                            break;
446
447 1117
                        case Opcodes::OP_CHECKSEQUENCEVERIFY:
448 12
                            if (!($flags & self::VERIFY_CHECKSEQUENCEVERIFY)) {
449 6
                                if ($flags & self::VERIFY_DISCOURAGE_UPGRADABLE_NOPS) {
450 1
                                    throw new ScriptRuntimeException(self::VERIFY_DISCOURAGE_UPGRADABLE_NOPS, 'Upgradable NOP found - this is discouraged');
451
                                }
452 5
                                break;
453
                            }
454
455 6
                            if ($mainStack->isEmpty()) {
456 1
                                throw new \RuntimeException('Invalid stack operation - CSV');
457
                            }
458
459 5
                            $sequence = Number::buffer($mainStack[-1], $minimal, 5, $this->math);
460 4
                            $nSequence = $sequence->getGmp();
461 4
                            if ($this->math->cmp($nSequence, gmp_init(0)) < 0) {
462 1
                                throw new ScriptRuntimeException(self::VERIFY_CHECKSEQUENCEVERIFY, 'Negative locktime');
463
                            }
464
465 3
                            if ($this->math->cmp($this->math->bitwiseAnd($nSequence, gmp_init(TransactionInputInterface::SEQUENCE_LOCKTIME_DISABLE_FLAG, 10)), gmp_init(0)) !== 0) {
466 1
                                break;
467
                            }
468
469 2
                            if (!$checker->checkSequence($sequence)) {
470 2
                                throw new ScriptRuntimeException(self::VERIFY_CHECKSEQUENCEVERIFY, 'Unsatisfied sequence');
471
                            }
472
                            break;
473
474 1110
                        case Opcodes::OP_NOP1:
475 1109
                        case Opcodes::OP_NOP4:
476 1108
                        case Opcodes::OP_NOP5:
477 1107
                        case Opcodes::OP_NOP6:
478 1106
                        case Opcodes::OP_NOP7:
479 1105
                        case Opcodes::OP_NOP8:
480 1104
                        case Opcodes::OP_NOP9:
481 1103
                        case Opcodes::OP_NOP10:
482 27
                            if ($flags & self::VERIFY_DISCOURAGE_UPGRADABLE_NOPS) {
483 10
                                throw new ScriptRuntimeException(self::VERIFY_DISCOURAGE_UPGRADABLE_NOPS, 'Upgradable NOP found - this is discouraged');
484
                            }
485 17
                            break;
486
487 1100
                        case Opcodes::OP_NOP:
488 84
                            break;
489
490 1077
                        case Opcodes::OP_IF:
491 1055
                        case Opcodes::OP_NOTIF:
492
                            // <expression> if [statements] [else [statements]] endif
493 247
                            $value = false;
494 247
                            if ($fExec) {
495 247
                                if ($mainStack->isEmpty()) {
496 2
                                    throw new \RuntimeException('Unbalanced conditional');
497
                                }
498
499 245
                                $buffer = Number::buffer($mainStack->pop(), $minimal)->getBuffer();
500 245
                                $value = $this->castToBool($buffer);
501 245
                                if ($opCode === Opcodes::OP_NOTIF) {
502 17
                                    $value = !$value;
503
                                }
504
                            }
505 245
                            $vfStack->push($value);
506 245
                            break;
507
508 1053
                        case Opcodes::OP_ELSE:
509 115
                            if ($vfStack->isEmpty()) {
510 4
                                throw new \RuntimeException('Unbalanced conditional');
511
                            }
512 113
                            $vfStack->push(!$vfStack->pop());
513 113
                            break;
514
515 1050
                        case Opcodes::OP_ENDIF:
516 147
                            if ($vfStack->isEmpty()) {
517 7
                                throw new \RuntimeException('Unbalanced conditional');
518
                            }
519 143
                            $vfStack->pop();
520 143
                            break;
521
522 914
                        case Opcodes::OP_VERIFY:
523 30
                            if ($mainStack->isEmpty()) {
524 1
                                throw new \RuntimeException('Invalid stack operation');
525
                            }
526 29
                            $value = $this->castToBool($mainStack[-1]);
527 29
                            if (!$value) {
528 1
                                throw new \RuntimeException('Error: verify');
529
                            }
530 28
                            $mainStack->pop();
531 28
                            break;
532
533 907
                        case Opcodes::OP_TOALTSTACK:
534 8
                            if ($mainStack->isEmpty()) {
535 1
                                throw new \RuntimeException('Invalid stack operation OP_TOALTSTACK');
536
                            }
537 7
                            $altStack->push($mainStack->pop());
538 7
                            break;
539
540 905
                        case Opcodes::OP_FROMALTSTACK:
541 5
                            if ($altStack->isEmpty()) {
542 2
                                throw new \RuntimeException('Invalid alt-stack operation OP_FROMALTSTACK');
543
                            }
544 3
                            $mainStack->push($altStack->pop());
545 3
                            break;
546
547 902
                        case Opcodes::OP_IFDUP:
548
                            // If top value not zero, duplicate it.
549 6
                            if ($mainStack->isEmpty()) {
550 2
                                throw new \RuntimeException('Invalid stack operation OP_IFDUP');
551
                            }
552 4
                            $vch = $mainStack[-1];
553 4
                            if ($this->castToBool($vch)) {
554 3
                                $mainStack->push($vch);
555
                            }
556 4
                            break;
557
558 899
                        case Opcodes::OP_DEPTH:
559 78
                            $num = count($mainStack);
560 78
                            $depth = Number::int($num)->getBuffer();
561 78
                            $mainStack->push($depth);
562 78
                            break;
563
564 890
                        case Opcodes::OP_DROP:
565 48
                            if ($mainStack->isEmpty()) {
566 2
                                throw new \RuntimeException('Invalid stack operation OP_DROP');
567
                            }
568 46
                            $mainStack->pop();
569 46
                            break;
570
571 887
                        case Opcodes::OP_DUP:
572 43
                            if ($mainStack->isEmpty()) {
573 2
                                throw new \RuntimeException('Invalid stack operation OP_DUP');
574
                            }
575 41
                            $vch = $mainStack[-1];
576 41
                            $mainStack->push($vch);
577 41
                            break;
578
579 878
                        case Opcodes::OP_NIP:
580 6
                            if (count($mainStack) < 2) {
581 3
                                throw new \RuntimeException('Invalid stack operation OP_NIP');
582
                            }
583 3
                            unset($mainStack[-2]);
584 3
                            break;
585
586 872
                        case Opcodes::OP_OVER:
587 6
                            if (count($mainStack) < 2) {
588 3
                                throw new \RuntimeException('Invalid stack operation OP_OVER');
589
                            }
590 3
                            $vch = $mainStack[-2];
591 3
                            $mainStack->push($vch);
592 3
                            break;
593
594 868
                        case Opcodes::OP_ROT:
595 12
                            if (count($mainStack) < 3) {
596 4
                                throw new \RuntimeException('Invalid stack operation OP_ROT');
597
                            }
598 8
                            $mainStack->swap(-3, -2);
599 8
                            $mainStack->swap(-2, -1);
600 8
                            break;
601
602 862
                        case Opcodes::OP_SWAP:
603 10
                            if (count($mainStack) < 2) {
604 3
                                throw new \RuntimeException('Invalid stack operation OP_SWAP');
605
                            }
606 7
                            $mainStack->swap(-2, -1);
607 7
                            break;
608
609 858
                        case Opcodes::OP_TUCK:
610 6
                            if (count($mainStack) < 2) {
611 3
                                throw new \RuntimeException('Invalid stack operation OP_TUCK');
612
                            }
613 3
                            $vch = $mainStack[-1];
614 3
                            $mainStack->add(- 2, $vch);
615 3
                            break;
616
617 854
                        case Opcodes::OP_PICK:
618 845
                        case Opcodes::OP_ROLL:
619 29
                            if (count($mainStack) < 2) {
620 4
                                throw new \RuntimeException('Invalid stack operation OP_PICK');
621
                            }
622
623 25
                            $n = Number::buffer($mainStack[-1], $minimal, 4)->getGmp();
624 23
                            $mainStack->pop();
625 23
                            if ($this->math->cmp($n, gmp_init(0)) < 0 || $this->math->cmp($n, gmp_init(count($mainStack))) >= 0) {
626 5
                                throw new \RuntimeException('Invalid stack operation OP_PICK');
627
                            }
628
629 18
                            $pos = (int) gmp_strval($this->math->sub($this->math->sub(gmp_init(0), $n), gmp_init(1)), 10);
630 18
                            $vch = $mainStack[$pos];
631 18
                            if ($opCode === Opcodes::OP_ROLL) {
632 9
                                unset($mainStack[$pos]);
633
                            }
634 18
                            $mainStack->push($vch);
635 18
                            break;
636
637 837
                        case Opcodes::OP_2DROP:
638 9
                            if (count($mainStack) < 2) {
639 1
                                throw new \RuntimeException('Invalid stack operation OP_2DROP');
640
                            }
641 8
                            $mainStack->pop();
642 8
                            $mainStack->pop();
643 8
                            break;
644
645 835
                        case Opcodes::OP_2DUP:
646 6
                            if (count($mainStack) < 2) {
647 3
                                throw new \RuntimeException('Invalid stack operation OP_2DUP');
648
                            }
649 3
                            $string1 = $mainStack[-2];
650 3
                            $string2 = $mainStack[-1];
651 3
                            $mainStack->push($string1);
652 3
                            $mainStack->push($string2);
653 3
                            break;
654
655 831
                        case Opcodes::OP_3DUP:
656 11
                            if (count($mainStack) < 3) {
657 4
                                throw new \RuntimeException('Invalid stack operation OP_3DUP');
658
                            }
659 7
                            $string1 = $mainStack[-3];
660 7
                            $string2 = $mainStack[-2];
661 7
                            $string3 = $mainStack[-1];
662 7
                            $mainStack->push($string1);
663 7
                            $mainStack->push($string2);
664 7
                            $mainStack->push($string3);
665 7
                            break;
666
667 821
                        case Opcodes::OP_2OVER:
668 5
                            if (count($mainStack) < 4) {
669 3
                                throw new \RuntimeException('Invalid stack operation OP_2OVER');
670
                            }
671 2
                            $string1 = $mainStack[-4];
672 2
                            $string2 = $mainStack[-3];
673 2
                            $mainStack->push($string1);
674 2
                            $mainStack->push($string2);
675 2
                            break;
676
677 817
                        case Opcodes::OP_2ROT:
678 10
                            if (count($mainStack) < 6) {
679 1
                                throw new \RuntimeException('Invalid stack operation OP_2ROT');
680
                            }
681 9
                            $string1 = $mainStack[-6];
682 9
                            $string2 = $mainStack[-5];
683 9
                            unset($mainStack[-6], $mainStack[-5]);
684 9
                            $mainStack->push($string1);
685 9
                            $mainStack->push($string2);
686 9
                            break;
687
688 815
                        case Opcodes::OP_2SWAP:
689 5
                            if (count($mainStack) < 4) {
690 3
                                throw new \RuntimeException('Invalid stack operation OP_2SWAP');
691
                            }
692 2
                            $mainStack->swap(-3, -1);
693 2
                            $mainStack->swap(-4, -2);
694 2
                            break;
695
696 811
                        case Opcodes::OP_SIZE:
697 31
                            if ($mainStack->isEmpty()) {
698 2
                                throw new \RuntimeException('Invalid stack operation OP_SIZE');
699
                            }
700 29
                            $size = Number::int($mainStack[-1]->getSize());
701 29
                            $mainStack->push($size->getBuffer());
702 29
                            break;
703
704 808
                        case Opcodes::OP_EQUAL:
705 697
                        case Opcodes::OP_EQUALVERIFY:
706 308
                            if (count($mainStack) < 2) {
707 4
                                throw new \RuntimeException('Invalid stack operation OP_EQUAL');
708
                            }
709
710 304
                            $equal = $mainStack[-2]->equals($mainStack[-1]);
711 304
                            $mainStack->pop();
712 304
                            $mainStack->pop();
713 304
                            $mainStack->push($equal ? $this->vchTrue : $this->vchFalse);
714 304
                            if ($opCode === Opcodes::OP_EQUALVERIFY) {
715 60
                                if ($equal) {
716 51
                                    $mainStack->pop();
717 10
                                } else {
718 9
                                    throw new \RuntimeException('Error EQUALVERIFY');
719
                                }
720 10
                            }
721
722 296
                            break;
723
724
                        // Arithmetic operations
725 666
                        case $opCode >= Opcodes::OP_1ADD && $opCode <= Opcodes::OP_0NOTEQUAL:
726 108
                            if ($mainStack->isEmpty()) {
727 6
                                throw new \Exception('Invalid stack operation 1ADD-OP_0NOTEQUAL');
728
                            }
729
730 102
                            $num = Number::buffer($mainStack[-1], $minimal)->getGmp();
731
732 79
                            if ($opCode === Opcodes::OP_1ADD) {
733 7
                                $num = $this->math->add($num, gmp_init(1));
734 72
                            } elseif ($opCode === Opcodes::OP_1SUB) {
735 3
                                $num = $this->math->sub($num, gmp_init(1));
736 69
                            } elseif ($opCode === Opcodes::OP_2MUL) {
737
                                $num = $this->math->mul(gmp_init(2), $num);
738 69
                            } elseif ($opCode === Opcodes::OP_NEGATE) {
739 4
                                $num = $this->math->sub(gmp_init(0), $num);
740 66
                            } elseif ($opCode === Opcodes::OP_ABS) {
741 5
                                if ($this->math->cmp($num, gmp_init(0)) < 0) {
742 5
                                    $num = $this->math->sub(gmp_init(0), $num);
743
                                }
744 61
                            } elseif ($opCode === Opcodes::OP_NOT) {
745 55
                                $num = gmp_init($this->math->cmp($num, gmp_init(0)) == 0 ? 1 : 0);
746 4
                            } else {
747
                                // is OP_0NOTEQUAL
748 6
                                $num = gmp_init($this->math->cmp($num, gmp_init(0)) != 0 ? 1 : 0);
749
                            }
750
751 79
                            $mainStack->pop();
752
753 79
                            $buffer = Number::int(gmp_strval($num, 10))->getBuffer();
754
755 79
                            $mainStack->push($buffer);
756 79
                            break;
757
758 607
                        case $opCode >= Opcodes::OP_ADD && $opCode <= Opcodes::OP_MAX:
759 164
                            if (count($mainStack) < 2) {
760 13
                                throw new \Exception('Invalid stack operation (OP_ADD - OP_MAX)');
761
                            }
762
763 151
                            $num1 = Number::buffer($mainStack[-2], $minimal)->getGmp();
764 134
                            $num2 = Number::buffer($mainStack[-1], $minimal)->getGmp();
765
766 121
                            if ($opCode === Opcodes::OP_ADD) {
767 30
                                $num = $this->math->add($num1, $num2);
768 97
                            } else if ($opCode === Opcodes::OP_SUB) {
769 6
                                $num = $this->math->sub($num1, $num2);
770 91
                            } else if ($opCode === Opcodes::OP_BOOLAND) {
771 8
                                $num = $this->math->cmp($num1, gmp_init(0)) !== 0 && $this->math->cmp($num2, gmp_init(0)) !== 0;
772 83
                            } else if ($opCode === Opcodes::OP_BOOLOR) {
773 8
                                $num = $this->math->cmp($num1, gmp_init(0)) !== 0 || $this->math->cmp($num2, gmp_init(0)) !== 0;
774 75
                            } elseif ($opCode === Opcodes::OP_NUMEQUAL) {
775 28
                                $num = $this->math->cmp($num1, $num2) === 0;
776 55
                            } elseif ($opCode === Opcodes::OP_NUMEQUALVERIFY) {
777 4
                                $num = $this->math->cmp($num1, $num2) === 0;
778 51
                            } elseif ($opCode === Opcodes::OP_NUMNOTEQUAL) {
779 5
                                $num = $this->math->cmp($num1, $num2) !== 0;
780 46
                            } elseif ($opCode === Opcodes::OP_LESSTHAN) {
781 8
                                $num = $this->math->cmp($num1, $num2) < 0;
782 38
                            } elseif ($opCode === Opcodes::OP_GREATERTHAN) {
783 8
                                $num = $this->math->cmp($num1, $num2) > 0;
784 30
                            } elseif ($opCode === Opcodes::OP_LESSTHANOREQUAL) {
785 8
                                $num = $this->math->cmp($num1, $num2) <= 0;
786 22
                            } elseif ($opCode === Opcodes::OP_GREATERTHANOREQUAL) {
787 8
                                $num = $this->math->cmp($num1, $num2) >= 0;
788 14
                            } elseif ($opCode === Opcodes::OP_MIN) {
789 7
                                $num = ($this->math->cmp($num1, $num2) <= 0) ? $num1 : $num2;
790
                            } else {
791 7
                                $num = ($this->math->cmp($num1, $num2) >= 0) ? $num1 : $num2;
792
                            }
793
794 121
                            $mainStack->pop();
795 121
                            $mainStack->pop();
796 121
                            $buffer = Number::int(gmp_strval($num, 10))->getBuffer();
797 121
                            $mainStack->push($buffer);
798
799 121
                            if ($opCode === Opcodes::OP_NUMEQUALVERIFY) {
800 4
                                if ($this->castToBool($mainStack[-1])) {
801 4
                                    $mainStack->pop();
802
                                } else {
803
                                    throw new \RuntimeException('NUM EQUAL VERIFY error');
804
                                }
805
                            }
806 121
                            break;
807
808 443
                        case Opcodes::OP_WITHIN:
809 15
                            if (count($mainStack) < 3) {
810 1
                                throw new \RuntimeException('Invalid stack operation');
811
                            }
812
813 14
                            $num1 = Number::buffer($mainStack[-3], $minimal)->getGmp();
814 13
                            $num2 = Number::buffer($mainStack[-2], $minimal)->getGmp();
815 12
                            $num3 = Number::buffer($mainStack[-1], $minimal)->getGmp();
816
817 11
                            $value = $this->math->cmp($num2, $num1) <= 0 && $this->math->cmp($num1, $num3) < 0;
818 11
                            $mainStack->pop();
819 11
                            $mainStack->pop();
820 11
                            $mainStack->pop();
821 11
                            $mainStack->push($value ? $this->vchTrue : $this->vchFalse);
822 11
                            break;
823
824
                        // Hash operation
825 428
                        case Opcodes::OP_RIPEMD160:
826 422
                        case Opcodes::OP_SHA1:
827 414
                        case Opcodes::OP_SHA256:
828 408
                        case Opcodes::OP_HASH160:
829 385
                        case Opcodes::OP_HASH256:
830 100
                            if ($mainStack->isEmpty()) {
831 13
                                throw new \RuntimeException('Invalid stack operation');
832
                            }
833
834 87
                            $buffer = $mainStack[-1];
835 87
                            if ($opCode === Opcodes::OP_RIPEMD160) {
836 5
                                $hash = Hash::ripemd160($buffer);
837 83
                            } elseif ($opCode === Opcodes::OP_SHA1) {
838 6
                                $hash = Hash::sha1($buffer);
839 77
                            } elseif ($opCode === Opcodes::OP_SHA256) {
840 6
                                $hash = Hash::sha256($buffer);
841 73
                            } elseif ($opCode === Opcodes::OP_HASH160) {
842 68
                                $hash = Hash::sha256ripe160($buffer);
843 20
                            } else {
844 5
                                $hash = Hash::sha256d($buffer);
845
                            }
846
847 87
                            $mainStack->pop();
848 87
                            $mainStack->push($hash);
849 87
                            break;
850
851 374
                        case Opcodes::OP_CODESEPARATOR:
852 1
                            $hashStartPos = $parser->getPosition();
853 1
                            break;
854
855 373
                        case Opcodes::OP_CHECKSIG:
856 285
                        case Opcodes::OP_CHECKSIGVERIFY:
857 142
                            if (count($mainStack) < 2) {
858 2
                                throw new \RuntimeException('Invalid stack operation');
859
                            }
860
861 140
                            $vchPubKey = $mainStack[-1];
862 140
                            $vchSig = $mainStack[-2];
863
864 140
                            $scriptCode = new Script($script->getBuffer()->slice($hashStartPos));
865
866 140
                            $success = $checker->checkSig($scriptCode, $vchSig, $vchPubKey, $sigVersion, $flags);
867
868 80
                            $mainStack->pop();
869 80
                            $mainStack->pop();
870 80
                            $mainStack->push($success ? $this->vchTrue : $this->vchFalse);
871
872 80
                            if ($opCode === Opcodes::OP_CHECKSIGVERIFY) {
873
                                if ($success) {
874
                                    $mainStack->pop();
875
                                } else {
876
                                    throw new \RuntimeException('Checksig verify');
877
                                }
878
                            }
879 80
                            break;
880
881 231
                        case Opcodes::OP_CHECKMULTISIG:
882 154
                        case Opcodes::OP_CHECKMULTISIGVERIFY:
883 131
                            $i = 1;
884 131
                            if (count($mainStack) < $i) {
885 1
                                throw new \RuntimeException('Invalid stack operation');
886
                            }
887
888 130
                            $keyCount = Number::buffer($mainStack[-$i], $minimal)->getInt();
889 128
                            if ($keyCount < 0 || $keyCount > 20) {
890 2
                                throw new \RuntimeException('OP_CHECKMULTISIG: Public key count exceeds 20');
891
                            }
892
893 126
                            $opCount += $keyCount;
894 126
                            $this->checkOpcodeCount($opCount);
895
896
                            // Extract positions of the keys, and signatures, from the stack.
897 126
                            $ikey = ++$i;
898 126
                            $i += $keyCount; /** @var int $i */
899 126
                            if (count($mainStack) < $i) {
900 1
                                throw new \RuntimeException('Invalid stack operation');
901
                            }
902
903 125
                            $sigCount = Number::buffer($mainStack[-$i], $minimal)->getInt();
904 122
                            if ($sigCount < 0 || $sigCount > $keyCount) {
905 2
                                throw new \RuntimeException('Invalid Signature count');
906
                            }
907
908 120
                            $isig = ++$i;
909 120
                            $i += $sigCount;
910
911
                            // Extract the script since the last OP_CODESEPARATOR
912 120
                            $scriptCode = new Script($script->getBuffer()->slice($hashStartPos));
913
914 120
                            $fSuccess = true;
915 120
                            while ($fSuccess && $sigCount > 0) {
916
                                // Fetch the signature and public key
917 60
                                $sig = $mainStack[-$isig];
918 59
                                $pubkey = $mainStack[-$ikey];
919
920 59
                                if ($checker->checkSig($scriptCode, $sig, $pubkey, $sigVersion, $flags)) {
921 33
                                    $isig++;
922 33
                                    $sigCount--;
923 14
                                }
924
925 49
                                $ikey++;
926 49
                                $keyCount--;
927
928
                                // If there are more signatures left than keys left,
929
                                // then too many signatures have failed. Exit early,
930
                                // without checking any further signatures.
931 49
                                if ($sigCount > $keyCount) {
932 18
                                    $fSuccess = false;
933 4
                                }
934 18
                            }
935
936 103
                            while ($i-- > 1) {
937 103
                                $mainStack->pop();
938 14
                            }
939
940
                            // A bug causes CHECKMULTISIG to consume one extra argument
941
                            // whose contents were not checked in any way.
942
                            //
943
                            // Unfortunately this is a potential source of mutability,
944
                            // so optionally verify it is exactly equal to zero prior
945
                            // to removing it from the stack.
946 103
                            if ($mainStack->isEmpty()) {
947 1
                                throw new \RuntimeException('Invalid stack operation');
948
                            }
949
950 103
                            if ($flags & self::VERIFY_NULL_DUMMY && $mainStack[-1]->getSize() !== 0) {
951 2
                                throw new ScriptRuntimeException(self::VERIFY_NULL_DUMMY, 'Extra P2SH stack value should be OP_0');
952
                            }
953
954 101
                            $mainStack->pop();
955 101
                            $mainStack->push($fSuccess ? $this->vchTrue : $this->vchFalse);
956
957 101
                            if ($opCode === Opcodes::OP_CHECKMULTISIGVERIFY) {
958 30
                                if ($fSuccess) {
959 30
                                    $mainStack->pop();
960
                                } else {
961
                                    throw new \RuntimeException('OP_CHECKMULTISIG verify');
962
                                }
963
                            }
964 101
                            break;
965
966 6
                        default:
967 100
                            throw new \RuntimeException('Opcode not found');
968 6
                    }
969
970 1005
                    if (count($mainStack) + count($altStack) > 1000) {
971 1064
                        throw new \RuntimeException('Invalid stack size, exceeds 1000');
972
                    }
973 48
                }
974 90
            }
975
976 1141
            if (count($vfStack) !== 0) {
977 6
                throw new \RuntimeException('Unbalanced conditional at script end');
978
            }
979
980 1136
            return true;
981 448
        } catch (ScriptRuntimeException $e) {
982
            // echo "\n Runtime: " . $e->getMessage() . "\n" . $e->getTraceAsString() . PHP_EOL;
983
            // Failure due to script tags, can access flag: $e->getFailureFlag()
984 114
            return false;
985 334
        } catch (\Exception $e) {
986
            // echo "\n General: " . $e->getMessage()  . PHP_EOL . $e->getTraceAsString() . PHP_EOL;
987 334
            return false;
988
        }
989
    }
990
}
991