Completed
Pull Request — master (#331)
by thomas
34:30
created

Interpreter::verifyWitnessProgram()   C

Complexity

Conditions 12
Paths 22

Size

Total Lines 54
Code Lines 33

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 30
CRAP Score 12.1081

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 12
eloc 33
c 1
b 0
f 1
nc 22
nop 4
dl 0
loc 54
ccs 30
cts 33
cp 0.9091
crap 12.1081
rs 6.7848

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