Completed
Pull Request — master (#285)
by thomas
21:56
created

Interpreter::checkOpcodeCount()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 2
Bugs 0 Features 1
Metric Value
c 2
b 0
f 1
dl 0
loc 8
ccs 4
cts 4
cp 1
rs 9.4285
cc 2
eloc 4
nc 2
nop 0
crap 2
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 int
27
     */
28
    private $opCount;
29
30
    /**
31
     * @var \BitWasp\Bitcoin\Math\Math
32
     */
33
    private $math;
34
35
    /**
36
     * @var BufferInterface
37
     */
38
    private $vchFalse;
39
40
    /**
41
     * @var BufferInterface
42
     */
43
    private $vchTrue;
44
45
    /**
46
     * @var array
47
     */
48
    private $disabledOps = [
49
        Opcodes::OP_CAT,    Opcodes::OP_SUBSTR, Opcodes::OP_LEFT,  Opcodes::OP_RIGHT,
50
        Opcodes::OP_INVERT, Opcodes::OP_AND,    Opcodes::OP_OR,    Opcodes::OP_XOR,
51
        Opcodes::OP_2MUL,   Opcodes::OP_2DIV,   Opcodes::OP_MUL,   Opcodes::OP_DIV,
52
        Opcodes::OP_MOD,    Opcodes::OP_LSHIFT, Opcodes::OP_RSHIFT
53
    ];
54
55
    /**
56
     * @param EcAdapterInterface $ecAdapter
57
     */
58 816
    public function __construct(EcAdapterInterface $ecAdapter)
59
    {
60 816
        $this->math = $ecAdapter->getMath();
61 816
        $this->vchFalse = new Buffer("", 0, $this->math);
62 816
        $this->vchTrue = new Buffer("\x01", 1, $this->math);
63 816
    }
64
65
    /**
66
     * Cast the value to a boolean
67
     *
68
     * @param BufferInterface $value
69
     * @return bool
70
     */
71 498
    public function castToBool(BufferInterface $value)
72
    {
73 498
        $val = $value->getBinary();
74 498
        for ($i = 0, $size = strlen($val); $i < $size; $i++) {
75 492
            $chr = ord($val[$i]);
76 492
            if ($chr != 0) {
77 480
                if ($i == ($size - 1) && $chr == 0x80) {
78
                    return false;
79
                }
80
81 480
                return true;
82
            }
83 12
        }
84
85 18
        return false;
86
    }
87
88
    /**
89
     * @param BufferInterface $signature
90
     * @return bool
91
     */
92
    public function isValidSignatureEncoding(BufferInterface $signature)
93
    {
94
        try {
95
            TransactionSignature::isDERSignature($signature);
96
            return true;
97
        } catch (SignatureNotCanonical $e) {
98
            /* In any case, we will return false outside this block */
99
        }
100
101
        return false;
102
    }
103
104
    /**
105
     * @param int $opCode
106
     * @param BufferInterface $pushData
107
     * @return bool
108
     * @throws \Exception
109
     */
110 12
    public function checkMinimalPush($opCode, BufferInterface $pushData)
111
    {
112 12
        $pushSize = $pushData->getSize();
113 12
        $binary = $pushData->getBinary();
114
115 12
        if ($pushSize === 0) {
116 6
            return $opCode === Opcodes::OP_0;
117 12
        } elseif ($pushSize === 1) {
118 6
            $first = ord($binary[0]);
119 6
            if ($first >= 1 && $first <= 16) {
120 6
                return $opCode === (Opcodes::OP_1 + ($first - 1));
121 6
            } elseif ($first === 0x81) {
122 6
                return $opCode === Opcodes::OP_1NEGATE;
123
            }
124 12
        } elseif ($pushSize <= 75) {
125 12
            return $opCode === $pushSize;
126 6
        } elseif ($pushSize <= 255) {
127 6
            return $opCode === Opcodes::OP_PUSHDATA1;
128 6
        } elseif ($pushSize <= 65535) {
129 6
            return $opCode === Opcodes::OP_PUSHDATA2;
130
        }
131
132 6
        return true;
133
    }
134
135
    /**
136
     * @return $this
137
     * @throws \Exception
138
     */
139 774
    private function checkOpcodeCount()
140
    {
141 774
        if ($this->math->cmp($this->opCount, 201) > 0) {
142 6
            throw new \RuntimeException('Error: Script op code count');
143
        }
144
145 774
        return $this;
146
    }
147
148
    /**
149
     * @param WitnessProgram $witnessProgram
150
     * @param ScriptWitness $scriptWitness
151
     * @param int $flags
152
     * @param Checker $checker
153
     * @return bool
154
     */
155 30
    private function verifyWitnessProgram(WitnessProgram $witnessProgram, ScriptWitness $scriptWitness, $flags, Checker $checker)
156
    {
157 30
        $witnessCount = count($scriptWitness);
158
159 30
        if ($witnessProgram->getVersion() == 0) {
160 30
            $buffer = $witnessProgram->getProgram();
161 30
            if ($buffer->getSize() === 32) {
162
                // Version 0 segregated witness program: SHA256(Script) in program, Script + inputs in witness
163 18
                if ($witnessCount === 0) {
164
                    // Must contain script at least
165
                    return false;
166
                }
167
168 18
                $scriptPubKey = new Script($scriptWitness[$witnessCount - 1]);
169 24
                $stackValues = $scriptWitness->slice(0, -1);
170 18
                $hashScriptPubKey = Hash::sha256($scriptPubKey->getBuffer());
171
172 18
                if ($hashScriptPubKey == $buffer) {
173
                    return false;
174
                }
175 30
            } elseif ($buffer->getSize() === 20) {
176
                // Version 0 special case for pay-to-pubkeyhash
177 12
                if ($witnessCount !== 2) {
178
                    // 2 items in witness - <signature> <pubkey>
179
                    return false;
180
                }
181
182 12
                $scriptPubKey = ScriptFactory::create()->sequence([Opcodes::OP_DUP, Opcodes::OP_HASH160, $buffer, Opcodes::OP_EQUALVERIFY, Opcodes::OP_CHECKSIG])->getScript();
183 12
                $stackValues = $scriptWitness;
184 12
            } else {
185
                return false;
186
            }
187 30
        } elseif ($flags & self::VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM) {
188
            return false;
189
        } else {
190
            return false;
191
        }
192
193 30
        $mainStack = new Stack();
194 30
        foreach ($stackValues as $value) {
195 30
            $mainStack->push($value);
196 30
        }
197
198 30
        if (!$this->evaluate($scriptPubKey, $mainStack, 1, $flags, $checker)) {
199
            return false;
200
        }
201
202 30
        if ($mainStack->count() !== 1) {
203
            return false;
204
        }
205
206 30
        if (!$this->castToBool($mainStack->bottom())) {
207
            return false;
208
        }
209
210 30
        return true;
211
    }
212
213
    /**
214
     * @param ScriptInterface $scriptSig
215
     * @param ScriptInterface $scriptPubKey
216
     * @param int $flags
217
     * @param Checker $checker
218
     * @param ScriptWitnessInterface|null $witness
219
     * @return bool
220
     */
221 804
    public function verify(ScriptInterface $scriptSig, ScriptInterface $scriptPubKey, $flags, Checker $checker, ScriptWitnessInterface $witness = null)
222
    {
223 804
        static $emptyWitness = null;
224 804
        if ($emptyWitness === null) {
225 6
            $emptyWitness = new ScriptWitness([]);
226 6
        }
227
228 804
        $witness = $witness ?: $emptyWitness;
229
230 804
        if (($flags & self::VERIFY_SIGPUSHONLY) != 0 && !$scriptSig->isPushOnly()) {
231
            return false;
232
        }
233
234 804
        $stack = new Stack();
235 804
        if (!$this->evaluate($scriptSig, $stack, 0, $flags, $checker)) {
236 6
            return false;
237
        }
238
239 798
        $backup = [];
240 798
        if ($flags & self::VERIFY_P2SH) {
241 108
            foreach ($stack as $s) {
242 78
                $backup[] = $s;
243 108
            }
244 108
        }
245
246 798
        if (!$this->evaluate($scriptPubKey, $stack, 0, $flags, $checker)) {
247 300
            return false;
248
        }
249
250 498
        if ($stack->isEmpty()) {
251 6
            return false;
252
        }
253
254 492
        if (false === $this->castToBool($stack[-1])) {
255 12
            return false;
256
        }
257
258 480
        $program = null;
259
260 480
        if ($flags & self::VERIFY_WITNESS) {
261 72
            if ($scriptPubKey->isWitness($program)) {
0 ignored issues
show
Documentation introduced by
$program is of type null, but the function expects a object<BitWasp\Bitcoin\Script\WitnessProgram>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
262
                /** @var WitnessProgram $program */
263 18
                if ($scriptSig->getBuffer()->getSize() !== 0) {
264
                    return false;
265
                }
266
267 18
                if (!$this->verifyWitnessProgram($program, $witness, $flags, $checker)) {
0 ignored issues
show
Documentation introduced by
$witness is of type null|object<BitWasp\Bitc...ScriptWitnessInterface>, but the function expects a object<BitWasp\Bitcoin\Script\ScriptWitness>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
268
                    return false;
269
                }
270
271 18
                $stack->resize(1);
272 18
            }
273 72
        }
274
275 480
        if ($flags & self::VERIFY_P2SH && (new OutputClassifier($scriptPubKey))->isPayToScriptHash()) {
276 36
            if (!$scriptSig->isPushOnly()) {
277 6
                return false;
278
            }
279
280 30
            $stack = new Stack();
281 30
            foreach ($backup as $i) {
282 30
                $stack->push($i);
283 30
            }
284
285
            // Restore mainStack to how it was after evaluating scriptSig
286 30
            if ($stack->isEmpty()) {
287
                return false;
288
            }
289
290
            // Load redeemscript as the scriptPubKey
291 30
            $scriptPubKey = new Script($stack->bottom());
292 30
            $stack->pop();
293
294 30
            if (!$this->evaluate($scriptPubKey, $stack, 0, $flags, $checker)) {
295 6
                return false;
296
            }
297
298 24
            if ($stack->isEmpty()) {
299
                return false;
300
            }
301
302 24
            if (!$this->castToBool($stack->bottom())) {
303
                return false;
304
            }
305
306 24
            if ($flags & self::VERIFY_WITNESS) {
307 24
                if ($scriptPubKey->isWitness($program)) {
308
                    /** @var WitnessProgram $program */
309 12
                    if ($scriptSig != (ScriptFactory::create()->push($scriptPubKey->getBuffer())->getScript())) {
310
                        return false; // SCRIPT_ERR_WITNESS_MALLEATED_P2SH
311
                    }
312
313 12
                    if (!$this->verifyWitnessProgram($program, $witness, $flags, $checker)) {
0 ignored issues
show
Documentation introduced by
$witness is of type null|object<BitWasp\Bitc...ScriptWitnessInterface>, but the function expects a object<BitWasp\Bitcoin\Script\ScriptWitness>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

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