Completed
Push — master ( 267ea0...3cd95b )
by thomas
22:33
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 0
Metric Value
cc 2
eloc 4
nc 2
nop 1
dl 0
loc 8
ccs 4
cts 4
cp 1
crap 2
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
namespace BitWasp\Bitcoin\Script\Interpreter;
4
5
use BitWasp\Bitcoin\Bitcoin;
6
use BitWasp\Bitcoin\Crypto\EcAdapter\Adapter\EcAdapterInterface;
7
use BitWasp\Bitcoin\Crypto\Hash;
8
use BitWasp\Bitcoin\Exceptions\SignatureNotCanonical;
9
use BitWasp\Bitcoin\Exceptions\ScriptRuntimeException;
10
use BitWasp\Bitcoin\Script\Classifier\OutputClassifier;
11
use BitWasp\Bitcoin\Script\Opcodes;
12
use BitWasp\Bitcoin\Script\Script;
13
use BitWasp\Bitcoin\Script\ScriptFactory;
14
use BitWasp\Bitcoin\Script\ScriptInterface;
15
use BitWasp\Bitcoin\Script\ScriptWitness;
16
use BitWasp\Bitcoin\Script\ScriptWitnessInterface;
17
use BitWasp\Bitcoin\Script\WitnessProgram;
18
use BitWasp\Bitcoin\Signature\TransactionSignature;
19
use BitWasp\Bitcoin\Transaction\SignatureHash\SigHash;
20
use BitWasp\Bitcoin\Transaction\TransactionInputInterface;
21
use BitWasp\Buffertools\Buffer;
22
use BitWasp\Buffertools\BufferInterface;
23
24
class Interpreter implements InterpreterInterface
25
{
26
27
    /**
28
     * @var \BitWasp\Bitcoin\Math\Math
29
     */
30
    private $math;
31
32
    /**
33
     * @var BufferInterface
34
     */
35
    private $vchFalse;
36
37
    /**
38
     * @var BufferInterface
39
     */
40
    private $vchTrue;
41
42
    /**
43
     * @var array
44
     */
45
    private $disabledOps = [
46
        Opcodes::OP_CAT,    Opcodes::OP_SUBSTR, Opcodes::OP_LEFT,  Opcodes::OP_RIGHT,
47
        Opcodes::OP_INVERT, Opcodes::OP_AND,    Opcodes::OP_OR,    Opcodes::OP_XOR,
48
        Opcodes::OP_2MUL,   Opcodes::OP_2DIV,   Opcodes::OP_MUL,   Opcodes::OP_DIV,
49
        Opcodes::OP_MOD,    Opcodes::OP_LSHIFT, Opcodes::OP_RSHIFT
50
    ];
51
52
    /**
53
     * @param EcAdapterInterface $ecAdapter
54
     */
55 138
    public function __construct(EcAdapterInterface $ecAdapter = null)
56
    {
57 138
        $ecAdapter = $ecAdapter ?: Bitcoin::getEcAdapter();
58 138
        $this->math = $ecAdapter->getMath();
59 138
        $this->vchFalse = new Buffer("", 0, $this->math);
60 138
        $this->vchTrue = new Buffer("\x01", 1, $this->math);
61 138
    }
62
63
    /**
64
     * Cast the value to a boolean
65
     *
66
     * @param BufferInterface $value
67
     * @return bool
68
     */
69 1692
    public function castToBool(BufferInterface $value)
70
    {
71 1692
        $val = $value->getBinary();
72 1692
        for ($i = 0, $size = strlen($val); $i < $size; $i++) {
73 1550
            $chr = ord($val[$i]);
74 1550
            if ($chr !== 0) {
75 1544
                if (($i === ($size - 1)) && $chr === 0x80) {
76
                    return false;
77
                }
78 1544
                return true;
79
            }
80 2
        }
81 404
        return false;
82
    }
83
84
    /**
85
     * @param BufferInterface $signature
86
     * @return bool
87
     */
88
    public function isValidSignatureEncoding(BufferInterface $signature)
89
    {
90
        try {
91
            TransactionSignature::isDERSignature($signature);
92
            return true;
93
        } catch (SignatureNotCanonical $e) {
94
            /* In any case, we will return false outside this block */
95
        }
96
97
        return false;
98
    }
99
100
    /**
101
     * @param int $opCode
102
     * @param BufferInterface $pushData
103
     * @return bool
104
     * @throws \Exception
105
     */
106 236
    public function checkMinimalPush($opCode, BufferInterface $pushData)
107
    {
108 236
        $pushSize = $pushData->getSize();
109 236
        $binary = $pushData->getBinary();
110
111 236
        if ($pushSize === 0) {
112 114
            return $opCode === Opcodes::OP_0;
113 194
        } elseif ($pushSize === 1) {
114 50
            $first = ord($binary[0]);
115
116 50
            if ($first >= 1 && $first <= 16) {
117 38
                return $opCode === (Opcodes::OP_1 + ($first - 1));
118 18
            } elseif ($first === 0x81) {
119 18
                return $opCode === Opcodes::OP_1NEGATE;
120
            }
121 150
        } elseif ($pushSize <= 75) {
122 146
            return $opCode === $pushSize;
123 10
        } elseif ($pushSize <= 255) {
124 8
            return $opCode === Opcodes::OP_PUSHDATA1;
125 8
        } elseif ($pushSize <= 65535) {
126 8
            return $opCode === Opcodes::OP_PUSHDATA2;
127
        }
128
129 16
        return true;
130
    }
131
132
    /**
133
     * @param int $count
134
     * @return $this
135
     */
136 2246
    private function checkOpcodeCount($count)
137
    {
138 2246
        if ($count > 201) {
139 10
            throw new \RuntimeException('Error: Script op code count');
140
        }
141
142 2246
        return $this;
143
    }
144
145
    /**
146
     * @param WitnessProgram $witnessProgram
147
     * @param ScriptWitnessInterface $scriptWitness
148
     * @param int $flags
149
     * @param Checker $checker
150
     * @return bool
151
     */
152 54
    private function verifyWitnessProgram(WitnessProgram $witnessProgram, ScriptWitnessInterface $scriptWitness, $flags, Checker $checker)
153
    {
154 53
        $witnessCount = count($scriptWitness);
155
156 53
        if ($witnessProgram->getVersion() === 0) {
157 51
            $buffer = $witnessProgram->getProgram();
158 51
            if ($buffer->getSize() === 32) {
159
                // Version 0 segregated witness program: SHA256(Script) in program, Script + inputs in witness
160 29
                if ($witnessCount === 0) {
161
                    // Must contain script at least
162 2
                    return false;
163
                }
164
165 27
                $scriptPubKey = new Script($scriptWitness[$witnessCount - 1]);
166 27
                $stackValues = $scriptWitness->slice(0, -1);
167 27
                $hashScriptPubKey = Hash::sha256($scriptPubKey->getBuffer());
168
169 27
                if (!$hashScriptPubKey->equals($buffer)) {
0 ignored issues
show
Documentation introduced by
$buffer is of type object<BitWasp\Buffertools\BufferInterface>, but the function expects a object<self>.

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...
170 24
                    return false;
171
                }
172 25
            } elseif ($buffer->getSize() === 20) {
173
                // Version 0 special case for pay-to-pubkeyhash
174 20
                if ($witnessCount !== 2) {
175
                    // 2 items in witness - <signature> <pubkey>
176 4
                    return false;
177
                }
178
179 18
                $scriptPubKey = ScriptFactory::scriptPubKey()->payToPubKeyHash($buffer);
180 18
                $stackValues = $scriptWitness;
181 2
            } else {
182 38
                return false;
183
            }
184 7
        } elseif ($flags & self::VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM) {
185 2
            return false;
186
        } else {
187
            return false;
188
        }
189
190 41
        $mainStack = new Stack();
191 41
        foreach ($stackValues as $value) {
192 39
            $mainStack->push($value);
193 5
        }
194
195 41
        if (!$this->evaluate($scriptPubKey, $mainStack, SigHash::V1, $flags, $checker)) {
196
            return false;
197
        }
198
199 41
        if ($mainStack->count() !== 1) {
200
            return false;
201
        }
202
203 41
        if (!$this->castToBool($mainStack->bottom())) {
204 18
            return false;
205
        }
206
207 23
        return true;
208
    }
209
210
    /**
211
     * @param ScriptInterface $scriptSig
212
     * @param ScriptInterface $scriptPubKey
213
     * @param int $flags
214
     * @param Checker $checker
215
     * @param ScriptWitnessInterface|null $witness
216
     * @return bool
217
     */
218 2374
    public function verify(ScriptInterface $scriptSig, ScriptInterface $scriptPubKey, $flags, Checker $checker, ScriptWitnessInterface $witness = null)
219
    {
220 2374
        static $emptyWitness = null;
221 2374
        if ($emptyWitness === null) {
222 6
            $emptyWitness = new ScriptWitness([]);
223 2
        }
224
225 2374
        $witness = is_null($witness) ? $emptyWitness : $witness;
226
227 2374
        if (($flags & self::VERIFY_SIGPUSHONLY) !== 0 && !$scriptSig->isPushOnly()) {
228 4
            return false;
229
        }
230
231 2370
        $stack = new Stack();
232 2370
        if (!$this->evaluate($scriptSig, $stack, SigHash::V0, $flags, $checker)) {
233 116
            return false;
234
        }
235
236 2254
        $backup = [];
237 2254
        if ($flags & self::VERIFY_P2SH) {
238 1579
            foreach ($stack as $s) {
239 1278
                $backup[] = $s;
240 21
            }
241 21
        }
242
243 2254
        if (!$this->evaluate($scriptPubKey, $stack, SigHash::V0, $flags, $checker)) {
244 762
            return false;
245
        }
246
247 1492
        if ($stack->isEmpty()) {
248 26
            return false;
249
        }
250
251 1466
        if (false === $this->castToBool($stack[-1])) {
252 106
            return false;
253
        }
254
255 1360
        $program = null;
256 1360
        if ($flags & self::VERIFY_WITNESS) {
257 89
            if ($scriptPubKey->isWitness($program)) {
258
                /** @var WitnessProgram $program */
259 37
                if ($scriptSig->getBuffer()->getSize() !== 0) {
260 2
                    return false;
261
                }
262
263 35
                if (!$this->verifyWitnessProgram($program, $witness, $flags, $checker)) {
264 22
                    return false;
265
                }
266
267 13
                $stack->resize(1);
268 3
            }
269 15
        }
270
271 1336
        if ($flags & self::VERIFY_P2SH && (new OutputClassifier())->isPayToScriptHash($scriptPubKey)) {
272 77
            if (!$scriptSig->isPushOnly()) {
273 12
                return false;
274
            }
275
276 65
            $stack = new Stack();
277 65
            foreach ($backup as $i) {
278 65
                $stack->push($i);
279 7
            }
280
281
            // Restore mainStack to how it was after evaluating scriptSig
282 65
            if ($stack->isEmpty()) {
283
                return false;
284
            }
285
286
            // Load redeemscript as the scriptPubKey
287 65
            $scriptPubKey = new Script($stack->bottom());
288 65
            $stack->pop();
289
290 65
            if (!$this->evaluate($scriptPubKey, $stack, 0, $flags, $checker)) {
291 14
                return false;
292
            }
293
294 51
            if ($stack->isEmpty()) {
295
                return false;
296
            }
297
298 51
            if (!$this->castToBool($stack->bottom())) {
299 2
                return false;
300
            }
301
302 49
            if ($flags & self::VERIFY_WITNESS) {
303 29
                if ($scriptPubKey->isWitness($program)) {
304
                    /** @var WitnessProgram $program */
305 20
                    if (!$scriptSig->equals(ScriptFactory::sequence([$scriptPubKey->getBuffer()]))) {
306 2
                        return false; // SCRIPT_ERR_WITNESS_MALLEATED_P2SH
307
                    }
308
309 18
                    if (!$this->verifyWitnessProgram($program, $witness, $flags, $checker)) {
310 8
                        return false;
311
                    }
312
313 10
                    $stack->resize(1);
314 2
                }
315 5
            }
316 5
        }
317
318 1298
        if ($flags & self::VERIFY_CLEAN_STACK) {
319 24
            if (!($flags & self::VERIFY_P2SH !== 0) && ($flags & self::VERIFY_WITNESS !== 0)) {
320
                return false; // implied flags required
321
            }
322
323 24
            if (count($stack) !== 1) {
324 4
                return false; // Cleanstack
325
            }
326 6
        }
327
328 1294
        if ($flags & self::VERIFY_WITNESS) {
329 55
            if (!$flags & self::VERIFY_P2SH) {
330
                return false; //
331
            }
332
333 55
            if ($program === null && !$witness->isNull()) {
334 2
                return false; // SCRIPT_ERR_WITNESS_UNEXPECTED
335
            }
336 15
        }
337
338 1292
        return true;
339
    }
340
341
    /**
342
     * @param Stack $vfStack
343
     * @param bool $value
344
     * @return bool
345
     */
346 2374
    private function checkExec(Stack $vfStack, $value)
347
    {
348 2374
        $ret = 0;
349 2374
        foreach ($vfStack as $item) {
350 484
            if ($item === $value) {
351 484
                $ret++;
352
            }
353 90
        }
354
355 2374
        return $ret;
356
    }
357
358
    /**
359
     * @param ScriptInterface $script
360
     * @param Stack $mainStack
361
     * @param int $sigVersion
362
     * @param int $flags
363
     * @param Checker $checker
364
     * @return bool
365
     */
366 2400
    public function evaluate(ScriptInterface $script, Stack $mainStack, $sigVersion, $flags, Checker $checker)
367
    {
368 2400
        $hashStartPos = 0;
369 2400
        $opCount = 0;
370 2400
        $zero = gmp_init(0, 10);
371 2400
        $altStack = new Stack();
372 2400
        $vfStack = new Stack();
373 2400
        $minimal = ($flags & self::VERIFY_MINIMALDATA) !== 0;
374 2400
        $parser = $script->getScriptParser();
375
376 2400
        if ($script->getBuffer()->getSize() > 10000) {
377 2
            return false;
378
        }
379
380
        try {
381 2400
            foreach ($parser as $operation) {
382 2374
                $opCode = $operation->getOp();
383 2374
                $pushData = $operation->getData();
384 2374
                $fExec = !$this->checkExec($vfStack, false);
385
386
                // If pushdata was written to
387 2374
                if ($operation->isPush() && $operation->getDataSize() > InterpreterInterface::MAX_SCRIPT_ELEMENT_SIZE) {
388 10
                    throw new \RuntimeException('Error - push size');
389
                }
390
391
                // OP_RESERVED should not count towards opCount
392 2368
                if ($opCode > Opcodes::OP_16 && ++$opCount) {
393 2246
                    $this->checkOpcodeCount($opCount);
394 86
                }
395
396 2368
                if (in_array($opCode, $this->disabledOps, true)) {
397 48
                    throw new \RuntimeException('Disabled Opcode');
398
                }
399
400 2368
                if ($fExec && $operation->isPush()) {
401
                    // In range of a pushdata opcode
402 1768
                    if ($minimal && !$this->checkMinimalPush($opCode, $pushData)) {
403 42
                        throw new ScriptRuntimeException(self::VERIFY_MINIMALDATA, 'Minimal pushdata required');
404
                    }
405
406 1726
                    $mainStack->push($pushData);
407
                    // echo " - [pushed '" . $pushData->getHex() . "']\n";
408 2294
                } elseif ($fExec || (Opcodes::OP_IF <= $opCode && $opCode <= Opcodes::OP_ENDIF)) {
409
                    // echo "OPCODE - " . $script->getOpcodes()->getOp($opCode) . "\n";
410
                    switch ($opCode) {
411 2292
                        case Opcodes::OP_1NEGATE:
412 2292
                        case Opcodes::OP_1:
413 2248
                        case Opcodes::OP_2:
414 2240
                        case Opcodes::OP_3:
415 2240
                        case Opcodes::OP_4:
416 2240
                        case Opcodes::OP_5:
417 2240
                        case Opcodes::OP_6:
418 2240
                        case Opcodes::OP_7:
419 2238
                        case Opcodes::OP_8:
420 2238
                        case Opcodes::OP_9:
421 2238
                        case Opcodes::OP_10:
422 2238
                        case Opcodes::OP_11:
423 2236
                        case Opcodes::OP_12:
424 2236
                        case Opcodes::OP_13:
425 2236
                        case Opcodes::OP_14:
426 2236
                        case Opcodes::OP_15:
427 2236
                        case Opcodes::OP_16:
428 1374
                            $num = \BitWasp\Bitcoin\Script\decodeOpN($opCode);
429 1374
                            $mainStack->push(Number::int($num)->getBuffer());
430 1374
                            break;
431
432 2236
                        case Opcodes::OP_CHECKLOCKTIMEVERIFY:
433 12
                            if (!($flags & self::VERIFY_CHECKLOCKTIMEVERIFY)) {
434 12
                                if ($flags & self::VERIFY_DISCOURAGE_UPGRADABLE_NOPS) {
435 2
                                    throw new ScriptRuntimeException(self::VERIFY_DISCOURAGE_UPGRADABLE_NOPS, 'Upgradable NOP found - this is discouraged');
436
                                }
437 10
                                break;
438
                            }
439
440
                            if ($mainStack->isEmpty()) {
441
                                throw new \RuntimeException('Invalid stack operation - CLTV');
442
                            }
443
444
                            $lockTime = Number::buffer($mainStack[-1], $minimal, 5, $this->math);
445
                            if (!$checker->checkLockTime($lockTime)) {
446
                                throw new ScriptRuntimeException(self::VERIFY_CHECKLOCKTIMEVERIFY, 'Unsatisfied locktime');
447
                            }
448
449
                            break;
450
451 2234
                        case Opcodes::OP_CHECKSEQUENCEVERIFY:
452 24
                            if (!($flags & self::VERIFY_CHECKSEQUENCEVERIFY)) {
453 12
                                if ($flags & self::VERIFY_DISCOURAGE_UPGRADABLE_NOPS) {
454 2
                                    throw new ScriptRuntimeException(self::VERIFY_DISCOURAGE_UPGRADABLE_NOPS, 'Upgradable NOP found - this is discouraged');
455
                                }
456 10
                                break;
457
                            }
458
459 12
                            if ($mainStack->isEmpty()) {
460 2
                                throw new \RuntimeException('Invalid stack operation - CSV');
461
                            }
462
463 10
                            $sequence = Number::buffer($mainStack[-1], $minimal, 5, $this->math);
464 8
                            $nSequence = $sequence->getGmp();
465 8
                            if ($this->math->cmp($nSequence, $zero) < 0) {
466 2
                                throw new ScriptRuntimeException(self::VERIFY_CHECKSEQUENCEVERIFY, 'Negative locktime');
467
                            }
468
469 6
                            if ($this->math->cmp($this->math->bitwiseAnd($nSequence, gmp_init(TransactionInputInterface::SEQUENCE_LOCKTIME_DISABLE_FLAG, 10)), $zero) !== 0) {
470 2
                                break;
471
                            }
472
473 4
                            if (!$checker->checkSequence($sequence)) {
474 4
                                throw new ScriptRuntimeException(self::VERIFY_CHECKSEQUENCEVERIFY, 'Unsatisfied sequence');
475
                            }
476
                            break;
477
478 2220
                        case Opcodes::OP_NOP1:
479 2218
                        case Opcodes::OP_NOP4:
480 2216
                        case Opcodes::OP_NOP5:
481 2214
                        case Opcodes::OP_NOP6:
482 2212
                        case Opcodes::OP_NOP7:
483 2210
                        case Opcodes::OP_NOP8:
484 2208
                        case Opcodes::OP_NOP9:
485 2206
                        case Opcodes::OP_NOP10:
486 54
                            if ($flags & self::VERIFY_DISCOURAGE_UPGRADABLE_NOPS) {
487 20
                                throw new ScriptRuntimeException(self::VERIFY_DISCOURAGE_UPGRADABLE_NOPS, 'Upgradable NOP found - this is discouraged');
488
                            }
489 34
                            break;
490
491 2200
                        case Opcodes::OP_NOP:
492 168
                            break;
493
494 2154
                        case Opcodes::OP_IF:
495 2110
                        case Opcodes::OP_NOTIF:
496
                            // <expression> if [statements] [else [statements]] endif
497 494
                            $value = false;
498 494
                            if ($fExec) {
499 494
                                if ($mainStack->isEmpty()) {
500 4
                                    throw new \RuntimeException('Unbalanced conditional');
501
                                }
502
503 490
                                $buffer = Number::buffer($mainStack->pop(), $minimal)->getBuffer();
0 ignored issues
show
Bug introduced by
It seems like $mainStack->pop() can be null; however, buffer() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
504 490
                                $value = $this->castToBool($buffer);
505 490
                                if ($opCode === Opcodes::OP_NOTIF) {
506 34
                                    $value = !$value;
507
                                }
508
                            }
509 490
                            $vfStack->push($value);
510 490
                            break;
511
512 2106
                        case Opcodes::OP_ELSE:
513 230
                            if ($vfStack->isEmpty()) {
514 8
                                throw new \RuntimeException('Unbalanced conditional');
515
                            }
516 226
                            $vfStack->push(!$vfStack->pop());
517 226
                            break;
518
519 2100
                        case Opcodes::OP_ENDIF:
520 294
                            if ($vfStack->isEmpty()) {
521 14
                                throw new \RuntimeException('Unbalanced conditional');
522
                            }
523 286
                            $vfStack->pop();
524 286
                            break;
525
526 1828
                        case Opcodes::OP_VERIFY:
527 60
                            if ($mainStack->isEmpty()) {
528 2
                                throw new \RuntimeException('Invalid stack operation');
529
                            }
530 58
                            $value = $this->castToBool($mainStack[-1]);
531 58
                            if (!$value) {
532 2
                                throw new \RuntimeException('Error: verify');
533
                            }
534 56
                            $mainStack->pop();
535 56
                            break;
536
537 1814
                        case Opcodes::OP_TOALTSTACK:
538 16
                            if ($mainStack->isEmpty()) {
539 2
                                throw new \RuntimeException('Invalid stack operation OP_TOALTSTACK');
540
                            }
541 14
                            $altStack->push($mainStack->pop());
542 14
                            break;
543
544 1810
                        case Opcodes::OP_FROMALTSTACK:
545 10
                            if ($altStack->isEmpty()) {
546 4
                                throw new \RuntimeException('Invalid alt-stack operation OP_FROMALTSTACK');
547
                            }
548 6
                            $mainStack->push($altStack->pop());
549 6
                            break;
550
551 1804
                        case Opcodes::OP_IFDUP:
552
                            // If top value not zero, duplicate it.
553 12
                            if ($mainStack->isEmpty()) {
554 4
                                throw new \RuntimeException('Invalid stack operation OP_IFDUP');
555
                            }
556 8
                            $vch = $mainStack[-1];
557 8
                            if ($this->castToBool($vch)) {
558 6
                                $mainStack->push($vch);
559
                            }
560 8
                            break;
561
562 1798
                        case Opcodes::OP_DEPTH:
563 156
                            $num = count($mainStack);
564 156
                            $depth = Number::int($num)->getBuffer();
565 156
                            $mainStack->push($depth);
566 156
                            break;
567
568 1780
                        case Opcodes::OP_DROP:
569 96
                            if ($mainStack->isEmpty()) {
570 4
                                throw new \RuntimeException('Invalid stack operation OP_DROP');
571
                            }
572 92
                            $mainStack->pop();
573 92
                            break;
574
575 1774
                        case Opcodes::OP_DUP:
576 86
                            if ($mainStack->isEmpty()) {
577 4
                                throw new \RuntimeException('Invalid stack operation OP_DUP');
578
                            }
579 82
                            $vch = $mainStack[-1];
580 82
                            $mainStack->push($vch);
581 82
                            break;
582
583 1756
                        case Opcodes::OP_NIP:
584 12
                            if (count($mainStack) < 2) {
585 6
                                throw new \RuntimeException('Invalid stack operation OP_NIP');
586
                            }
587 6
                            unset($mainStack[-2]);
588 6
                            break;
589
590 1744
                        case Opcodes::OP_OVER:
591 12
                            if (count($mainStack) < 2) {
592 6
                                throw new \RuntimeException('Invalid stack operation OP_OVER');
593
                            }
594 6
                            $vch = $mainStack[-2];
595 6
                            $mainStack->push($vch);
596 6
                            break;
597
598 1736
                        case Opcodes::OP_ROT:
599 24
                            if (count($mainStack) < 3) {
600 8
                                throw new \RuntimeException('Invalid stack operation OP_ROT');
601
                            }
602 16
                            $mainStack->swap(-3, -2);
603 16
                            $mainStack->swap(-2, -1);
604 16
                            break;
605
606 1724
                        case Opcodes::OP_SWAP:
607 20
                            if (count($mainStack) < 2) {
608 6
                                throw new \RuntimeException('Invalid stack operation OP_SWAP');
609
                            }
610 14
                            $mainStack->swap(-2, -1);
611 14
                            break;
612
613 1716
                        case Opcodes::OP_TUCK:
614 12
                            if (count($mainStack) < 2) {
615 6
                                throw new \RuntimeException('Invalid stack operation OP_TUCK');
616
                            }
617 6
                            $vch = $mainStack[-1];
618 6
                            $mainStack->add(- 2, $vch);
619 6
                            break;
620
621 1708
                        case Opcodes::OP_PICK:
622 1690
                        case Opcodes::OP_ROLL:
623 58
                            if (count($mainStack) < 2) {
624 8
                                throw new \RuntimeException('Invalid stack operation OP_PICK');
625
                            }
626
627 50
                            $n = Number::buffer($mainStack[-1], $minimal, 4)->getGmp();
628 46
                            $mainStack->pop();
629 46
                            if ($this->math->cmp($n, $zero) < 0 || $this->math->cmp($n, gmp_init(count($mainStack))) >= 0) {
630 10
                                throw new \RuntimeException('Invalid stack operation OP_PICK');
631
                            }
632
633 36
                            $pos = (int) gmp_strval($this->math->sub($this->math->sub($zero, $n), gmp_init(1)), 10);
634 36
                            $vch = $mainStack[$pos];
635 36
                            if ($opCode === Opcodes::OP_ROLL) {
636 18
                                unset($mainStack[$pos]);
637
                            }
638 36
                            $mainStack->push($vch);
639 36
                            break;
640
641 1674
                        case Opcodes::OP_2DROP:
642 18
                            if (count($mainStack) < 2) {
643 2
                                throw new \RuntimeException('Invalid stack operation OP_2DROP');
644
                            }
645 16
                            $mainStack->pop();
646 16
                            $mainStack->pop();
647 16
                            break;
648
649 1670
                        case Opcodes::OP_2DUP:
650 12
                            if (count($mainStack) < 2) {
651 6
                                throw new \RuntimeException('Invalid stack operation OP_2DUP');
652
                            }
653 6
                            $string1 = $mainStack[-2];
654 6
                            $string2 = $mainStack[-1];
655 6
                            $mainStack->push($string1);
656 6
                            $mainStack->push($string2);
657 6
                            break;
658
659 1662
                        case Opcodes::OP_3DUP:
660 22
                            if (count($mainStack) < 3) {
661 8
                                throw new \RuntimeException('Invalid stack operation OP_3DUP');
662
                            }
663 14
                            $string1 = $mainStack[-3];
664 14
                            $string2 = $mainStack[-2];
665 14
                            $string3 = $mainStack[-1];
666 14
                            $mainStack->push($string1);
667 14
                            $mainStack->push($string2);
668 14
                            $mainStack->push($string3);
669 14
                            break;
670
671 1642
                        case Opcodes::OP_2OVER:
672 10
                            if (count($mainStack) < 4) {
673 6
                                throw new \RuntimeException('Invalid stack operation OP_2OVER');
674
                            }
675 4
                            $string1 = $mainStack[-4];
676 4
                            $string2 = $mainStack[-3];
677 4
                            $mainStack->push($string1);
678 4
                            $mainStack->push($string2);
679 4
                            break;
680
681 1634
                        case Opcodes::OP_2ROT:
682 20
                            if (count($mainStack) < 6) {
683 2
                                throw new \RuntimeException('Invalid stack operation OP_2ROT');
684
                            }
685 18
                            $string1 = $mainStack[-6];
686 18
                            $string2 = $mainStack[-5];
687 18
                            unset($mainStack[-6], $mainStack[-5]);
688 18
                            $mainStack->push($string1);
689 18
                            $mainStack->push($string2);
690 18
                            break;
691
692 1630
                        case Opcodes::OP_2SWAP:
693 10
                            if (count($mainStack) < 4) {
694 6
                                throw new \RuntimeException('Invalid stack operation OP_2SWAP');
695
                            }
696 4
                            $mainStack->swap(-3, -1);
697 4
                            $mainStack->swap(-4, -2);
698 4
                            break;
699
700 1622
                        case Opcodes::OP_SIZE:
701 62
                            if ($mainStack->isEmpty()) {
702 4
                                throw new \RuntimeException('Invalid stack operation OP_SIZE');
703
                            }
704 58
                            $size = Number::int($mainStack[-1]->getSize());
705 58
                            $mainStack->push($size->getBuffer());
706 58
                            break;
707
708 1616
                        case Opcodes::OP_EQUAL:
709 1394
                        case Opcodes::OP_EQUALVERIFY:
710 616
                            if (count($mainStack) < 2) {
711 8
                                throw new \RuntimeException('Invalid stack operation OP_EQUAL');
712
                            }
713
714 608
                            $equal = $mainStack[-2]->equals($mainStack[-1]);
715 608
                            $mainStack->pop();
716 608
                            $mainStack->pop();
717 608
                            $mainStack->push($equal ? $this->vchTrue : $this->vchFalse);
718 608
                            if ($opCode === Opcodes::OP_EQUALVERIFY) {
719 120
                                if ($equal) {
720 102
                                    $mainStack->pop();
721 10
                                } else {
722 18
                                    throw new \RuntimeException('Error EQUALVERIFY');
723
                                }
724 10
                            }
725
726 592
                            break;
727
728
                        // Arithmetic operations
729 1332
                        case $opCode >= Opcodes::OP_1ADD && $opCode <= Opcodes::OP_0NOTEQUAL:
730 216
                            if ($mainStack->isEmpty()) {
731 12
                                throw new \Exception('Invalid stack operation 1ADD-OP_0NOTEQUAL');
732
                            }
733
734 204
                            $num = Number::buffer($mainStack[-1], $minimal)->getGmp();
735
736 158
                            if ($opCode === Opcodes::OP_1ADD) {
737 14
                                $num = $this->math->add($num, gmp_init(1));
738 144
                            } elseif ($opCode === Opcodes::OP_1SUB) {
739 6
                                $num = $this->math->sub($num, gmp_init(1));
740 138
                            } elseif ($opCode === Opcodes::OP_2MUL) {
741
                                $num = $this->math->mul(gmp_init(2), $num);
742 138
                            } elseif ($opCode === Opcodes::OP_NEGATE) {
743 8
                                $num = $this->math->sub($zero, $num);
744 132
                            } elseif ($opCode === Opcodes::OP_ABS) {
745 10
                                if ($this->math->cmp($num, $zero) < 0) {
746 10
                                    $num = $this->math->sub($zero, $num);
747
                                }
748 122
                            } elseif ($opCode === Opcodes::OP_NOT) {
749 110
                                $num = gmp_init($this->math->cmp($num, $zero) === 0 ? 1 : 0);
750 4
                            } else {
751
                                // is OP_0NOTEQUAL
752 12
                                $num = gmp_init($this->math->cmp($num, $zero) !== 0 ? 1 : 0);
753
                            }
754
755 158
                            $mainStack->pop();
756
757 158
                            $buffer = Number::int(gmp_strval($num, 10))->getBuffer();
758
759 158
                            $mainStack->push($buffer);
760 158
                            break;
761
762 1214
                        case $opCode >= Opcodes::OP_ADD && $opCode <= Opcodes::OP_MAX:
763 328
                            if (count($mainStack) < 2) {
764 26
                                throw new \Exception('Invalid stack operation (OP_ADD - OP_MAX)');
765
                            }
766
767 302
                            $num1 = Number::buffer($mainStack[-2], $minimal)->getGmp();
768 268
                            $num2 = Number::buffer($mainStack[-1], $minimal)->getGmp();
769
770 242
                            if ($opCode === Opcodes::OP_ADD) {
771 60
                                $num = $this->math->add($num1, $num2);
772 194
                            } else if ($opCode === Opcodes::OP_SUB) {
773 12
                                $num = $this->math->sub($num1, $num2);
774 182
                            } else if ($opCode === Opcodes::OP_BOOLAND) {
775 16
                                $num = $this->math->cmp($num1, $zero) !== 0 && $this->math->cmp($num2, $zero) !== 0;
776 166
                            } else if ($opCode === Opcodes::OP_BOOLOR) {
777 16
                                $num = $this->math->cmp($num1, $zero) !== 0 || $this->math->cmp($num2, $zero) !== 0;
778 150
                            } elseif ($opCode === Opcodes::OP_NUMEQUAL) {
779 56
                                $num = $this->math->cmp($num1, $num2) === 0;
780 110
                            } elseif ($opCode === Opcodes::OP_NUMEQUALVERIFY) {
781 8
                                $num = $this->math->cmp($num1, $num2) === 0;
782 102
                            } elseif ($opCode === Opcodes::OP_NUMNOTEQUAL) {
783 10
                                $num = $this->math->cmp($num1, $num2) !== 0;
784 92
                            } elseif ($opCode === Opcodes::OP_LESSTHAN) {
785 16
                                $num = $this->math->cmp($num1, $num2) < 0;
786 76
                            } elseif ($opCode === Opcodes::OP_GREATERTHAN) {
787 16
                                $num = $this->math->cmp($num1, $num2) > 0;
788 60
                            } elseif ($opCode === Opcodes::OP_LESSTHANOREQUAL) {
789 16
                                $num = $this->math->cmp($num1, $num2) <= 0;
790 44
                            } elseif ($opCode === Opcodes::OP_GREATERTHANOREQUAL) {
791 16
                                $num = $this->math->cmp($num1, $num2) >= 0;
792 28
                            } elseif ($opCode === Opcodes::OP_MIN) {
793 14
                                $num = ($this->math->cmp($num1, $num2) <= 0) ? $num1 : $num2;
794
                            } else {
795 14
                                $num = ($this->math->cmp($num1, $num2) >= 0) ? $num1 : $num2;
796
                            }
797
798 242
                            $mainStack->pop();
799 242
                            $mainStack->pop();
800 242
                            $buffer = Number::int(gmp_strval($num, 10))->getBuffer();
801 242
                            $mainStack->push($buffer);
802
803 242
                            if ($opCode === Opcodes::OP_NUMEQUALVERIFY) {
804 8
                                if ($this->castToBool($mainStack[-1])) {
805 8
                                    $mainStack->pop();
806
                                } else {
807
                                    throw new \RuntimeException('NUM EQUAL VERIFY error');
808
                                }
809
                            }
810 242
                            break;
811
812 886
                        case Opcodes::OP_WITHIN:
813 30
                            if (count($mainStack) < 3) {
814 2
                                throw new \RuntimeException('Invalid stack operation');
815
                            }
816
817 28
                            $num1 = Number::buffer($mainStack[-3], $minimal)->getGmp();
818 26
                            $num2 = Number::buffer($mainStack[-2], $minimal)->getGmp();
819 24
                            $num3 = Number::buffer($mainStack[-1], $minimal)->getGmp();
820
821 22
                            $value = $this->math->cmp($num2, $num1) <= 0 && $this->math->cmp($num1, $num3) < 0;
822 22
                            $mainStack->pop();
823 22
                            $mainStack->pop();
824 22
                            $mainStack->pop();
825 22
                            $mainStack->push($value ? $this->vchTrue : $this->vchFalse);
826 22
                            break;
827
828
                        // Hash operation
829 856
                        case Opcodes::OP_RIPEMD160:
830 844
                        case Opcodes::OP_SHA1:
831 828
                        case Opcodes::OP_SHA256:
832 816
                        case Opcodes::OP_HASH160:
833 766
                        case Opcodes::OP_HASH256:
834 200
                            if ($mainStack->isEmpty()) {
835 26
                                throw new \RuntimeException('Invalid stack operation');
836
                            }
837
838 174
                            $buffer = $mainStack[-1];
839 174
                            if ($opCode === Opcodes::OP_RIPEMD160) {
840 10
                                $hash = Hash::ripemd160($buffer);
841 166
                            } elseif ($opCode === Opcodes::OP_SHA1) {
842 12
                                $hash = Hash::sha1($buffer);
843 154
                            } elseif ($opCode === Opcodes::OP_SHA256) {
844 12
                                $hash = Hash::sha256($buffer);
845 146
                            } elseif ($opCode === Opcodes::OP_HASH160) {
846 136
                                $hash = Hash::sha256ripe160($buffer);
847 20
                            } else {
848 10
                                $hash = Hash::sha256d($buffer);
849
                            }
850
851 174
                            $mainStack->pop();
852 174
                            $mainStack->push($hash);
853 174
                            break;
854
855 748
                        case Opcodes::OP_CODESEPARATOR:
856 2
                            $hashStartPos = $parser->getPosition();
857 2
                            break;
858
859 746
                        case Opcodes::OP_CHECKSIG:
860 516
                        case Opcodes::OP_CHECKSIGVERIFY:
861 284
                            if (count($mainStack) < 2) {
862 4
                                throw new \RuntimeException('Invalid stack operation');
863
                            }
864
865 280
                            $vchPubKey = $mainStack[-1];
866 280
                            $vchSig = $mainStack[-2];
867
868 280
                            $scriptCode = new Script($script->getBuffer()->slice($hashStartPos));
869
870 280
                            $success = $checker->checkSig($scriptCode, $vchSig, $vchPubKey, $sigVersion, $flags);
871
872 160
                            $mainStack->pop();
873 160
                            $mainStack->pop();
874 160
                            $mainStack->push($success ? $this->vchTrue : $this->vchFalse);
875
876 160
                            if ($opCode === Opcodes::OP_CHECKSIGVERIFY) {
877
                                if ($success) {
878
                                    $mainStack->pop();
879
                                } else {
880
                                    throw new \RuntimeException('Checksig verify');
881
                                }
882
                            }
883 160
                            break;
884
885 462
                        case Opcodes::OP_CHECKMULTISIG:
886 286
                        case Opcodes::OP_CHECKMULTISIGVERIFY:
887 262
                            $i = 1;
888 262
                            if (count($mainStack) < $i) {
889 2
                                throw new \RuntimeException('Invalid stack operation');
890
                            }
891
892 260
                            $keyCount = Number::buffer($mainStack[-$i], $minimal)->getInt();
893 256
                            if ($keyCount < 0 || $keyCount > 20) {
894 4
                                throw new \RuntimeException('OP_CHECKMULTISIG: Public key count exceeds 20');
895
                            }
896
897 252
                            $opCount += $keyCount;
898 252
                            $this->checkOpcodeCount($opCount);
899
900
                            // Extract positions of the keys, and signatures, from the stack.
901 252
                            $ikey = ++$i;
902 252
                            $i += $keyCount;
903 252
                            if (count($mainStack) < $i) {
904 2
                                throw new \RuntimeException('Invalid stack operation');
905
                            }
906
907 250
                            $sigCount = Number::buffer($mainStack[-$i], $minimal)->getInt();
908 244
                            if ($sigCount < 0 || $sigCount > $keyCount) {
909 4
                                throw new \RuntimeException('Invalid Signature count');
910
                            }
911
912 240
                            $isig = ++$i;
913 240
                            $i += $sigCount;
914
915
                            // Extract the script since the last OP_CODESEPARATOR
916 240
                            $scriptCode = new Script($script->getBuffer()->slice($hashStartPos));
917
918 240
                            $fSuccess = true;
919 240
                            while ($fSuccess && $sigCount > 0) {
920
                                // Fetch the signature and public key
921 120
                                $sig = $mainStack[-$isig];
922 118
                                $pubkey = $mainStack[-$ikey];
923
924 118
                                if ($checker->checkSig($scriptCode, $sig, $pubkey, $sigVersion, $flags)) {
925 66
                                    $isig++;
926 66
                                    $sigCount--;
927 14
                                }
928
929 98
                                $ikey++;
930 98
                                $keyCount--;
931
932
                                // If there are more signatures left than keys left,
933
                                // then too many signatures have failed. Exit early,
934
                                // without checking any further signatures.
935 98
                                if ($sigCount > $keyCount) {
936 36
                                    $fSuccess = false;
937 4
                                }
938 18
                            }
939
940 206
                            while ($i-- > 1) {
941 206
                                $mainStack->pop();
942 14
                            }
943
944
                            // A bug causes CHECKMULTISIG to consume one extra argument
945
                            // whose contents were not checked in any way.
946
                            //
947
                            // Unfortunately this is a potential source of mutability,
948
                            // so optionally verify it is exactly equal to zero prior
949
                            // to removing it from the stack.
950 206
                            if ($mainStack->isEmpty()) {
951 2
                                throw new \RuntimeException('Invalid stack operation');
952
                            }
953
954 206
                            if ($flags & self::VERIFY_NULL_DUMMY && $mainStack[-1]->getSize() !== 0) {
955 4
                                throw new ScriptRuntimeException(self::VERIFY_NULL_DUMMY, 'Extra P2SH stack value should be OP_0');
956
                            }
957
958 202
                            $mainStack->pop();
959 202
                            $mainStack->push($fSuccess ? $this->vchTrue : $this->vchFalse);
960
961 202
                            if ($opCode === Opcodes::OP_CHECKMULTISIGVERIFY) {
962 60
                                if ($fSuccess) {
963 60
                                    $mainStack->pop();
964
                                } else {
965
                                    throw new \RuntimeException('OP_CHECKMULTISIG verify');
966
                                }
967
                            }
968 202
                            break;
969
970 6
                        default:
971 200
                            throw new \RuntimeException('Opcode not found');
972 6
                    }
973
974 2010
                    if (count($mainStack) + count($altStack) > 1000) {
975 2212
                        throw new \RuntimeException('Invalid stack size, exceeds 1000');
976
                    }
977 48
                }
978 94
            }
979
980 2294
            if (count($vfStack) !== 0) {
981 12
                throw new \RuntimeException('Unbalanced conditional at script end');
982
            }
983
984 2284
            return true;
985 896
        } catch (ScriptRuntimeException $e) {
986
            // echo "\n Runtime: " . $e->getMessage() . "\n" . $e->getTraceAsString() . PHP_EOL;
987
            // Failure due to script tags, can access flag: $e->getFailureFlag()
988 228
            return false;
989 668
        } catch (\Exception $e) {
990
            // echo "\n General: " . $e->getMessage()  . PHP_EOL . $e->getTraceAsString() . PHP_EOL;
991 668
            return false;
992
        }
993
    }
994
}
995