Completed
Pull Request — master (#335)
by thomas
04:14
created

Interpreter::checkExec()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 3.7898

Importance

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