Completed
Push — master ( 9023ba...e13b09 )
by thomas
27:04 queued 07:27
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
     * @return bool
341
     */
342 1187
    private function checkExec(Stack $vfStack, $value)
343
    {
344 1187
        $ret = 0;
345 1187
        foreach ($vfStack as $item) {
346 242
            if ($item == $value) {
347 242
                $ret++;
348
            }
349 90
        }
350
351 1187
        return $ret;
352
    }
353
354
    /**
355
     * @param ScriptInterface $script
356
     * @param Stack $mainStack
357
     * @param int $sigVersion
358
     * @param int $flags
359
     * @param Checker $checker
360
     * @return bool
361
     */
362 1194
    public function evaluate(ScriptInterface $script, Stack $mainStack, $sigVersion, $flags, Checker $checker)
363
    {
364 1194
        $hashStartPos = 0;
365 1194
        $opCount = 0;
366 1194
        $altStack = new Stack();
367 1194
        $vfStack = new Stack();
368 1194
        $minimal = ($flags & self::VERIFY_MINIMALDATA) != 0;
369 1194
        $parser = $script->getScriptParser();
370
371 1194
        if ($script->getBuffer()->getSize() > 10000) {
372 1
            return false;
373
        }
374
375
        try {
376 1194
            foreach ($parser as $operation) {
377 1187
                $opCode = $operation->getOp();
378 1187
                $pushData = $operation->getData();
379 1187
                $fExec = !$this->checkExec($vfStack, false);
380
381
                // If pushdata was written to
382 1187
                if ($operation->isPush() && $operation->getDataSize() > InterpreterInterface::MAX_SCRIPT_ELEMENT_SIZE) {
383 5
                    throw new \RuntimeException('Error - push size');
384
                }
385
386
                // OP_RESERVED should not count towards opCount
387 1184
                if ($opCode > Opcodes::OP_16 && ++$opCount) {
388 1123
                    $this->checkOpcodeCount($opCount);
389 86
                }
390
391 1184
                if (in_array($opCode, $this->disabledOps, true)) {
392 24
                    throw new \RuntimeException('Disabled Opcode');
393
                }
394
395 1184
                if ($fExec && $operation->isPush()) {
396
                    // In range of a pushdata opcode
397 884
                    if ($minimal && !$this->checkMinimalPush($opCode, $pushData)) {
398 21
                        throw new ScriptRuntimeException(self::VERIFY_MINIMALDATA, 'Minimal pushdata required');
399
                    }
400
401 863
                    $mainStack->push($pushData);
402
                    // echo " - [pushed '" . $pushData->getHex() . "']\n";
403 1148
                } elseif ($fExec || (Opcodes::OP_IF <= $opCode && $opCode <= Opcodes::OP_ENDIF)) {
404
                    // echo "OPCODE - " . $script->getOpcodes()->getOp($opCode) . "\n";
405
                    switch ($opCode) {
406 1146
                        case Opcodes::OP_1NEGATE:
407 1146
                        case Opcodes::OP_1:
408 1124
                        case Opcodes::OP_2:
409 1120
                        case Opcodes::OP_3:
410 1120
                        case Opcodes::OP_4:
411 1120
                        case Opcodes::OP_5:
412 1120
                        case Opcodes::OP_6:
413 1120
                        case Opcodes::OP_7:
414 1119
                        case Opcodes::OP_8:
415 1119
                        case Opcodes::OP_9:
416 1119
                        case Opcodes::OP_10:
417 1119
                        case Opcodes::OP_11:
418 1118
                        case Opcodes::OP_12:
419 1118
                        case Opcodes::OP_13:
420 1118
                        case Opcodes::OP_14:
421 1118
                        case Opcodes::OP_15:
422 1118
                        case Opcodes::OP_16:
423 687
                            $num = \BitWasp\Bitcoin\Script\decodeOpN($opCode);
424 687
                            $mainStack->push(Number::int($num)->getBuffer());
425 687
                            break;
426
427 1118
                        case Opcodes::OP_CHECKLOCKTIMEVERIFY:
428 6
                            if (!($flags & self::VERIFY_CHECKLOCKTIMEVERIFY)) {
429 6
                                if ($flags & self::VERIFY_DISCOURAGE_UPGRADABLE_NOPS) {
430 1
                                    throw new ScriptRuntimeException(self::VERIFY_DISCOURAGE_UPGRADABLE_NOPS, 'Upgradable NOP found - this is discouraged');
431
                                }
432 5
                                break;
433
                            }
434
435
                            if ($mainStack->isEmpty()) {
436
                                throw new \RuntimeException('Invalid stack operation - CLTV');
437
                            }
438
439
                            $lockTime = Number::buffer($mainStack[-1], $minimal, 5, $this->math);
440
                            if (!$checker->checkLockTime($lockTime)) {
441
                                throw new ScriptRuntimeException(self::VERIFY_CHECKLOCKTIMEVERIFY, 'Unsatisfied locktime');
442
                            }
443
444
                            break;
445
446 1117
                        case Opcodes::OP_CHECKSEQUENCEVERIFY:
447 12
                            if (!($flags & self::VERIFY_CHECKSEQUENCEVERIFY)) {
448 6
                                if ($flags & self::VERIFY_DISCOURAGE_UPGRADABLE_NOPS) {
449 1
                                    throw new ScriptRuntimeException(self::VERIFY_DISCOURAGE_UPGRADABLE_NOPS, 'Upgradable NOP found - this is discouraged');
450
                                }
451 5
                                break;
452
                            }
453
454 6
                            if ($mainStack->isEmpty()) {
455 1
                                throw new \RuntimeException('Invalid stack operation - CSV');
456
                            }
457
458 5
                            $sequence = Number::buffer($mainStack[-1], $minimal, 5, $this->math);
459 4
                            $nSequence = $sequence->getGmp();
460 4
                            if ($this->math->cmp($nSequence, gmp_init(0)) < 0) {
461 1
                                throw new ScriptRuntimeException(self::VERIFY_CHECKSEQUENCEVERIFY, 'Negative locktime');
462
                            }
463
464 3
                            if ($this->math->cmp($this->math->bitwiseAnd($nSequence, gmp_init(TransactionInputInterface::SEQUENCE_LOCKTIME_DISABLE_FLAG, 10)), gmp_init(0)) !== 0) {
465 1
                                break;
466
                            }
467
468 2
                            if (!$checker->checkSequence($sequence)) {
469 2
                                throw new ScriptRuntimeException(self::VERIFY_CHECKSEQUENCEVERIFY, 'Unsatisfied sequence');
470
                            }
471
                            break;
472
473 1110
                        case Opcodes::OP_NOP1:
474 1109
                        case Opcodes::OP_NOP4:
475 1108
                        case Opcodes::OP_NOP5:
476 1107
                        case Opcodes::OP_NOP6:
477 1106
                        case Opcodes::OP_NOP7:
478 1105
                        case Opcodes::OP_NOP8:
479 1104
                        case Opcodes::OP_NOP9:
480 1103
                        case Opcodes::OP_NOP10:
481 27
                            if ($flags & self::VERIFY_DISCOURAGE_UPGRADABLE_NOPS) {
482 10
                                throw new ScriptRuntimeException(self::VERIFY_DISCOURAGE_UPGRADABLE_NOPS, 'Upgradable NOP found - this is discouraged');
483
                            }
484 17
                            break;
485
486 1100
                        case Opcodes::OP_NOP:
487 84
                            break;
488
489 1077
                        case Opcodes::OP_IF:
490 1055
                        case Opcodes::OP_NOTIF:
491
                            // <expression> if [statements] [else [statements]] endif
492 247
                            $value = false;
493 247
                            if ($fExec) {
494 247
                                if ($mainStack->isEmpty()) {
495 2
                                    throw new \RuntimeException('Unbalanced conditional');
496
                                }
497
498 245
                                $buffer = Number::buffer($mainStack->pop(), $minimal)->getBuffer();
499 245
                                $value = $this->castToBool($buffer);
500 245
                                if ($opCode === Opcodes::OP_NOTIF) {
501 17
                                    $value = !$value;
502
                                }
503
                            }
504 245
                            $vfStack->push($value);
505 245
                            break;
506
507 1053
                        case Opcodes::OP_ELSE:
508 115
                            if ($vfStack->isEmpty()) {
509 4
                                throw new \RuntimeException('Unbalanced conditional');
510
                            }
511 113
                            $vfStack->push(!$vfStack->pop());
512 113
                            break;
513
514 1050
                        case Opcodes::OP_ENDIF:
515 147
                            if ($vfStack->isEmpty()) {
516 7
                                throw new \RuntimeException('Unbalanced conditional');
517
                            }
518 143
                            $vfStack->pop();
519 143
                            break;
520
521 914
                        case Opcodes::OP_VERIFY:
522 30
                            if ($mainStack->isEmpty()) {
523 1
                                throw new \RuntimeException('Invalid stack operation');
524
                            }
525 29
                            $value = $this->castToBool($mainStack[-1]);
526 29
                            if (!$value) {
527 1
                                throw new \RuntimeException('Error: verify');
528
                            }
529 28
                            $mainStack->pop();
530 28
                            break;
531
532 907
                        case Opcodes::OP_TOALTSTACK:
533 8
                            if ($mainStack->isEmpty()) {
534 1
                                throw new \RuntimeException('Invalid stack operation OP_TOALTSTACK');
535
                            }
536 7
                            $altStack->push($mainStack->pop());
537 7
                            break;
538
539 905
                        case Opcodes::OP_FROMALTSTACK:
540 5
                            if ($altStack->isEmpty()) {
541 2
                                throw new \RuntimeException('Invalid alt-stack operation OP_FROMALTSTACK');
542
                            }
543 3
                            $mainStack->push($altStack->pop());
544 3
                            break;
545
546 902
                        case Opcodes::OP_IFDUP:
547
                            // If top value not zero, duplicate it.
548 6
                            if ($mainStack->isEmpty()) {
549 2
                                throw new \RuntimeException('Invalid stack operation OP_IFDUP');
550
                            }
551 4
                            $vch = $mainStack[-1];
552 4
                            if ($this->castToBool($vch)) {
553 3
                                $mainStack->push($vch);
554
                            }
555 4
                            break;
556
557 899
                        case Opcodes::OP_DEPTH:
558 78
                            $num = count($mainStack);
559 78
                            $depth = Number::int($num)->getBuffer();
560 78
                            $mainStack->push($depth);
561 78
                            break;
562
563 890
                        case Opcodes::OP_DROP:
564 48
                            if ($mainStack->isEmpty()) {
565 2
                                throw new \RuntimeException('Invalid stack operation OP_DROP');
566
                            }
567 46
                            $mainStack->pop();
568 46
                            break;
569
570 887
                        case Opcodes::OP_DUP:
571 43
                            if ($mainStack->isEmpty()) {
572 2
                                throw new \RuntimeException('Invalid stack operation OP_DUP');
573
                            }
574 41
                            $vch = $mainStack[-1];
575 41
                            $mainStack->push($vch);
576 41
                            break;
577
578 878
                        case Opcodes::OP_NIP:
579 6
                            if (count($mainStack) < 2) {
580 3
                                throw new \RuntimeException('Invalid stack operation OP_NIP');
581
                            }
582 3
                            unset($mainStack[-2]);
583 3
                            break;
584
585 872
                        case Opcodes::OP_OVER:
586 6
                            if (count($mainStack) < 2) {
587 3
                                throw new \RuntimeException('Invalid stack operation OP_OVER');
588
                            }
589 3
                            $vch = $mainStack[-2];
590 3
                            $mainStack->push($vch);
591 3
                            break;
592
593 868
                        case Opcodes::OP_ROT:
594 12
                            if (count($mainStack) < 3) {
595 4
                                throw new \RuntimeException('Invalid stack operation OP_ROT');
596
                            }
597 8
                            $mainStack->swap(-3, -2);
598 8
                            $mainStack->swap(-2, -1);
599 8
                            break;
600
601 862
                        case Opcodes::OP_SWAP:
602 10
                            if (count($mainStack) < 2) {
603 3
                                throw new \RuntimeException('Invalid stack operation OP_SWAP');
604
                            }
605 7
                            $mainStack->swap(-2, -1);
606 7
                            break;
607
608 858
                        case Opcodes::OP_TUCK:
609 6
                            if (count($mainStack) < 2) {
610 3
                                throw new \RuntimeException('Invalid stack operation OP_TUCK');
611
                            }
612 3
                            $vch = $mainStack[-1];
613 3
                            $mainStack->add(- 2, $vch);
614 3
                            break;
615
616 854
                        case Opcodes::OP_PICK:
617 845
                        case Opcodes::OP_ROLL:
618 29
                            if (count($mainStack) < 2) {
619 4
                                throw new \RuntimeException('Invalid stack operation OP_PICK');
620
                            }
621
622 25
                            $n = Number::buffer($mainStack[-1], $minimal, 4)->getGmp();
623 23
                            $mainStack->pop();
624 23
                            if ($this->math->cmp($n, gmp_init(0)) < 0 || $this->math->cmp($n, gmp_init(count($mainStack))) >= 0) {
625 5
                                throw new \RuntimeException('Invalid stack operation OP_PICK');
626
                            }
627
628 18
                            $pos = (int) gmp_strval($this->math->sub($this->math->sub(gmp_init(0), $n), gmp_init(1)), 10);
629 18
                            $vch = $mainStack[$pos];
630 18
                            if ($opCode === Opcodes::OP_ROLL) {
631 9
                                unset($mainStack[$pos]);
632
                            }
633 18
                            $mainStack->push($vch);
634 18
                            break;
635
636 837
                        case Opcodes::OP_2DROP:
637 9
                            if (count($mainStack) < 2) {
638 1
                                throw new \RuntimeException('Invalid stack operation OP_2DROP');
639
                            }
640 8
                            $mainStack->pop();
641 8
                            $mainStack->pop();
642 8
                            break;
643
644 835
                        case Opcodes::OP_2DUP:
645 6
                            if (count($mainStack) < 2) {
646 3
                                throw new \RuntimeException('Invalid stack operation OP_2DUP');
647
                            }
648 3
                            $string1 = $mainStack[-2];
649 3
                            $string2 = $mainStack[-1];
650 3
                            $mainStack->push($string1);
651 3
                            $mainStack->push($string2);
652 3
                            break;
653
654 831
                        case Opcodes::OP_3DUP:
655 11
                            if (count($mainStack) < 3) {
656 4
                                throw new \RuntimeException('Invalid stack operation OP_3DUP');
657
                            }
658 7
                            $string1 = $mainStack[-3];
659 7
                            $string2 = $mainStack[-2];
660 7
                            $string3 = $mainStack[-1];
661 7
                            $mainStack->push($string1);
662 7
                            $mainStack->push($string2);
663 7
                            $mainStack->push($string3);
664 7
                            break;
665
666 821
                        case Opcodes::OP_2OVER:
667 5
                            if (count($mainStack) < 4) {
668 3
                                throw new \RuntimeException('Invalid stack operation OP_2OVER');
669
                            }
670 2
                            $string1 = $mainStack[-4];
671 2
                            $string2 = $mainStack[-3];
672 2
                            $mainStack->push($string1);
673 2
                            $mainStack->push($string2);
674 2
                            break;
675
676 817
                        case Opcodes::OP_2ROT:
677 10
                            if (count($mainStack) < 6) {
678 1
                                throw new \RuntimeException('Invalid stack operation OP_2ROT');
679
                            }
680 9
                            $string1 = $mainStack[-6];
681 9
                            $string2 = $mainStack[-5];
682 9
                            unset($mainStack[-6], $mainStack[-5]);
683 9
                            $mainStack->push($string1);
684 9
                            $mainStack->push($string2);
685 9
                            break;
686
687 815
                        case Opcodes::OP_2SWAP:
688 5
                            if (count($mainStack) < 4) {
689 3
                                throw new \RuntimeException('Invalid stack operation OP_2SWAP');
690
                            }
691 2
                            $mainStack->swap(-3, -1);
692 2
                            $mainStack->swap(-4, -2);
693 2
                            break;
694
695 811
                        case Opcodes::OP_SIZE:
696 31
                            if ($mainStack->isEmpty()) {
697 2
                                throw new \RuntimeException('Invalid stack operation OP_SIZE');
698
                            }
699 29
                            $size = Number::int($mainStack[-1]->getSize());
700 29
                            $mainStack->push($size->getBuffer());
701 29
                            break;
702
703 808
                        case Opcodes::OP_EQUAL:
704 697
                        case Opcodes::OP_EQUALVERIFY:
705 308
                            if (count($mainStack) < 2) {
706 4
                                throw new \RuntimeException('Invalid stack operation OP_EQUAL');
707
                            }
708
709 304
                            $equal = $mainStack[-2]->equals($mainStack[-1]);
710 304
                            $mainStack->pop();
711 304
                            $mainStack->pop();
712 304
                            $mainStack->push($equal ? $this->vchTrue : $this->vchFalse);
713 304
                            if ($opCode === Opcodes::OP_EQUALVERIFY) {
714 60
                                if ($equal) {
715 51
                                    $mainStack->pop();
716 10
                                } else {
717 9
                                    throw new \RuntimeException('Error EQUALVERIFY');
718
                                }
719 10
                            }
720
721 296
                            break;
722
723
                        // Arithmetic operations
724 666
                        case $opCode >= Opcodes::OP_1ADD && $opCode <= Opcodes::OP_0NOTEQUAL:
725 108
                            if ($mainStack->isEmpty()) {
726 6
                                throw new \Exception('Invalid stack operation 1ADD-OP_0NOTEQUAL');
727
                            }
728
729 102
                            $num = Number::buffer($mainStack[-1], $minimal)->getGmp();
730
731 79
                            if ($opCode === Opcodes::OP_1ADD) {
732 7
                                $num = $this->math->add($num, gmp_init(1));
733 72
                            } elseif ($opCode === Opcodes::OP_1SUB) {
734 3
                                $num = $this->math->sub($num, gmp_init(1));
735 69
                            } elseif ($opCode === Opcodes::OP_2MUL) {
736
                                $num = $this->math->mul(gmp_init(2), $num);
737 69
                            } elseif ($opCode === Opcodes::OP_NEGATE) {
738 4
                                $num = $this->math->sub(gmp_init(0), $num);
739 66
                            } elseif ($opCode === Opcodes::OP_ABS) {
740 5
                                if ($this->math->cmp($num, gmp_init(0)) < 0) {
741 5
                                    $num = $this->math->sub(gmp_init(0), $num);
742
                                }
743 61
                            } elseif ($opCode === Opcodes::OP_NOT) {
744 55
                                $num = gmp_init($this->math->cmp($num, gmp_init(0)) == 0 ? 1 : 0);
745 4
                            } else {
746
                                // is OP_0NOTEQUAL
747 6
                                $num = gmp_init($this->math->cmp($num, gmp_init(0)) != 0 ? 1 : 0);
748
                            }
749
750 79
                            $mainStack->pop();
751
752 79
                            $buffer = Number::int(gmp_strval($num, 10))->getBuffer();
753
754 79
                            $mainStack->push($buffer);
755 79
                            break;
756
757 607
                        case $opCode >= Opcodes::OP_ADD && $opCode <= Opcodes::OP_MAX:
758 164
                            if (count($mainStack) < 2) {
759 13
                                throw new \Exception('Invalid stack operation (OP_ADD - OP_MAX)');
760
                            }
761
762 151
                            $num1 = Number::buffer($mainStack[-2], $minimal)->getGmp();
763 134
                            $num2 = Number::buffer($mainStack[-1], $minimal)->getGmp();
764
765 121
                            if ($opCode === Opcodes::OP_ADD) {
766 30
                                $num = $this->math->add($num1, $num2);
767 97
                            } else if ($opCode === Opcodes::OP_SUB) {
768 6
                                $num = $this->math->sub($num1, $num2);
769 91
                            } else if ($opCode === Opcodes::OP_BOOLAND) {
770 8
                                $num = $this->math->cmp($num1, gmp_init(0)) !== 0 && $this->math->cmp($num2, gmp_init(0)) !== 0;
771 83
                            } else if ($opCode === Opcodes::OP_BOOLOR) {
772 8
                                $num = $this->math->cmp($num1, gmp_init(0)) !== 0 || $this->math->cmp($num2, gmp_init(0)) !== 0;
773 75
                            } elseif ($opCode === Opcodes::OP_NUMEQUAL) {
774 28
                                $num = $this->math->cmp($num1, $num2) === 0;
775 55
                            } elseif ($opCode === Opcodes::OP_NUMEQUALVERIFY) {
776 4
                                $num = $this->math->cmp($num1, $num2) === 0;
777 51
                            } elseif ($opCode === Opcodes::OP_NUMNOTEQUAL) {
778 5
                                $num = $this->math->cmp($num1, $num2) !== 0;
779 46
                            } elseif ($opCode === Opcodes::OP_LESSTHAN) {
780 8
                                $num = $this->math->cmp($num1, $num2) < 0;
781 38
                            } elseif ($opCode === Opcodes::OP_GREATERTHAN) {
782 8
                                $num = $this->math->cmp($num1, $num2) > 0;
783 30
                            } elseif ($opCode === Opcodes::OP_LESSTHANOREQUAL) {
784 8
                                $num = $this->math->cmp($num1, $num2) <= 0;
785 22
                            } elseif ($opCode === Opcodes::OP_GREATERTHANOREQUAL) {
786 8
                                $num = $this->math->cmp($num1, $num2) >= 0;
787 14
                            } elseif ($opCode === Opcodes::OP_MIN) {
788 7
                                $num = ($this->math->cmp($num1, $num2) <= 0) ? $num1 : $num2;
789
                            } else {
790 7
                                $num = ($this->math->cmp($num1, $num2) >= 0) ? $num1 : $num2;
791
                            }
792
793 121
                            $mainStack->pop();
794 121
                            $mainStack->pop();
795 121
                            $buffer = Number::int(gmp_strval($num, 10))->getBuffer();
796 121
                            $mainStack->push($buffer);
797
798 121
                            if ($opCode === Opcodes::OP_NUMEQUALVERIFY) {
799 4
                                if ($this->castToBool($mainStack[-1])) {
800 4
                                    $mainStack->pop();
801
                                } else {
802
                                    throw new \RuntimeException('NUM EQUAL VERIFY error');
803
                                }
804
                            }
805 121
                            break;
806
807 443
                        case Opcodes::OP_WITHIN:
808 15
                            if (count($mainStack) < 3) {
809 1
                                throw new \RuntimeException('Invalid stack operation');
810
                            }
811
812 14
                            $num1 = Number::buffer($mainStack[-3], $minimal)->getGmp();
813 13
                            $num2 = Number::buffer($mainStack[-2], $minimal)->getGmp();
814 12
                            $num3 = Number::buffer($mainStack[-1], $minimal)->getGmp();
815
816 11
                            $value = $this->math->cmp($num2, $num1) <= 0 && $this->math->cmp($num1, $num3) < 0;
817 11
                            $mainStack->pop();
818 11
                            $mainStack->pop();
819 11
                            $mainStack->pop();
820 11
                            $mainStack->push($value ? $this->vchTrue : $this->vchFalse);
821 11
                            break;
822
823
                        // Hash operation
824 428
                        case Opcodes::OP_RIPEMD160:
825 422
                        case Opcodes::OP_SHA1:
826 414
                        case Opcodes::OP_SHA256:
827 408
                        case Opcodes::OP_HASH160:
828 385
                        case Opcodes::OP_HASH256:
829 100
                            if ($mainStack->isEmpty()) {
830 13
                                throw new \RuntimeException('Invalid stack operation');
831
                            }
832
833 87
                            $buffer = $mainStack[-1];
834 87
                            if ($opCode === Opcodes::OP_RIPEMD160) {
835 5
                                $hash = Hash::ripemd160($buffer);
836 83
                            } elseif ($opCode === Opcodes::OP_SHA1) {
837 6
                                $hash = Hash::sha1($buffer);
838 77
                            } elseif ($opCode === Opcodes::OP_SHA256) {
839 6
                                $hash = Hash::sha256($buffer);
840 73
                            } elseif ($opCode === Opcodes::OP_HASH160) {
841 68
                                $hash = Hash::sha256ripe160($buffer);
842 20
                            } else {
843 5
                                $hash = Hash::sha256d($buffer);
844
                            }
845
846 87
                            $mainStack->pop();
847 87
                            $mainStack->push($hash);
848 87
                            break;
849
850 374
                        case Opcodes::OP_CODESEPARATOR:
851 1
                            $hashStartPos = $parser->getPosition();
852 1
                            break;
853
854 373
                        case Opcodes::OP_CHECKSIG:
855 285
                        case Opcodes::OP_CHECKSIGVERIFY:
856 142
                            if (count($mainStack) < 2) {
857 2
                                throw new \RuntimeException('Invalid stack operation');
858
                            }
859
860 140
                            $vchPubKey = $mainStack[-1];
861 140
                            $vchSig = $mainStack[-2];
862
863 140
                            $scriptCode = new Script($script->getBuffer()->slice($hashStartPos));
864
865 140
                            $success = $checker->checkSig($scriptCode, $vchSig, $vchPubKey, $sigVersion, $flags);
866
867 80
                            $mainStack->pop();
868 80
                            $mainStack->pop();
869 80
                            $mainStack->push($success ? $this->vchTrue : $this->vchFalse);
870
871 80
                            if ($opCode === Opcodes::OP_CHECKSIGVERIFY) {
872
                                if ($success) {
873
                                    $mainStack->pop();
874
                                } else {
875
                                    throw new \RuntimeException('Checksig verify');
876
                                }
877
                            }
878 80
                            break;
879
880 231
                        case Opcodes::OP_CHECKMULTISIG:
881 154
                        case Opcodes::OP_CHECKMULTISIGVERIFY:
882 131
                            $i = 1;
883 131
                            if (count($mainStack) < $i) {
884 1
                                throw new \RuntimeException('Invalid stack operation');
885
                            }
886
887 130
                            $keyCount = Number::buffer($mainStack[-$i], $minimal)->getInt();
888 128
                            if ($keyCount < 0 || $keyCount > 20) {
889 2
                                throw new \RuntimeException('OP_CHECKMULTISIG: Public key count exceeds 20');
890
                            }
891
892 126
                            $opCount += $keyCount;
893 126
                            $this->checkOpcodeCount($opCount);
894
895
                            // Extract positions of the keys, and signatures, from the stack.
896 126
                            $ikey = ++$i;
897 126
                            $i += $keyCount; /** @var int $i */
898 126
                            if (count($mainStack) < $i) {
899 1
                                throw new \RuntimeException('Invalid stack operation');
900
                            }
901
902 125
                            $sigCount = Number::buffer($mainStack[-$i], $minimal)->getInt();
903 122
                            if ($sigCount < 0 || $sigCount > $keyCount) {
904 2
                                throw new \RuntimeException('Invalid Signature count');
905
                            }
906
907 120
                            $isig = ++$i;
908 120
                            $i += $sigCount;
909
910
                            // Extract the script since the last OP_CODESEPARATOR
911 120
                            $scriptCode = new Script($script->getBuffer()->slice($hashStartPos));
912
913 120
                            $fSuccess = true;
914 120
                            while ($fSuccess && $sigCount > 0) {
915
                                // Fetch the signature and public key
916 60
                                $sig = $mainStack[-$isig];
917 59
                                $pubkey = $mainStack[-$ikey];
918
919 59
                                if ($checker->checkSig($scriptCode, $sig, $pubkey, $sigVersion, $flags)) {
920 33
                                    $isig++;
921 33
                                    $sigCount--;
922 14
                                }
923
924 49
                                $ikey++;
925 49
                                $keyCount--;
926
927
                                // If there are more signatures left than keys left,
928
                                // then too many signatures have failed. Exit early,
929
                                // without checking any further signatures.
930 49
                                if ($sigCount > $keyCount) {
931 18
                                    $fSuccess = false;
932 4
                                }
933 18
                            }
934
935 103
                            while ($i-- > 1) {
936 103
                                $mainStack->pop();
937 14
                            }
938
939
                            // A bug causes CHECKMULTISIG to consume one extra argument
940
                            // whose contents were not checked in any way.
941
                            //
942
                            // Unfortunately this is a potential source of mutability,
943
                            // so optionally verify it is exactly equal to zero prior
944
                            // to removing it from the stack.
945 103
                            if ($mainStack->isEmpty()) {
946 1
                                throw new \RuntimeException('Invalid stack operation');
947
                            }
948
949 103
                            if ($flags & self::VERIFY_NULL_DUMMY && $mainStack[-1]->getSize() !== 0) {
950 2
                                throw new ScriptRuntimeException(self::VERIFY_NULL_DUMMY, 'Extra P2SH stack value should be OP_0');
951
                            }
952
953 101
                            $mainStack->pop();
954 101
                            $mainStack->push($fSuccess ? $this->vchTrue : $this->vchFalse);
955
956 101
                            if ($opCode === Opcodes::OP_CHECKMULTISIGVERIFY) {
957 30
                                if ($fSuccess) {
958 30
                                    $mainStack->pop();
959
                                } else {
960
                                    throw new \RuntimeException('OP_CHECKMULTISIG verify');
961
                                }
962
                            }
963 101
                            break;
964
965 6
                        default:
966 100
                            throw new \RuntimeException('Opcode not found');
967 6
                    }
968
969 1005
                    if (count($mainStack) + count($altStack) > 1000) {
970 1064
                        throw new \RuntimeException('Invalid stack size, exceeds 1000');
971
                    }
972 48
                }
973 90
            }
974
975 1141
            if (count($vfStack) !== 0) {
976 6
                throw new \RuntimeException('Unbalanced conditional at script end');
977
            }
978
979 1136
            return true;
980 448
        } catch (ScriptRuntimeException $e) {
981
            // echo "\n Runtime: " . $e->getMessage() . "\n" . $e->getTraceAsString() . PHP_EOL;
982
            // Failure due to script tags, can access flag: $e->getFailureFlag()
983 114
            return false;
984 334
        } catch (\Exception $e) {
985
            // echo "\n General: " . $e->getMessage()  . PHP_EOL . $e->getTraceAsString() . PHP_EOL;
986 334
            return false;
987
        }
988
    }
989
}
990