Completed
Push — master ( 2a5c77...6a30c1 )
by thomas
52:06 queued 14:02
created

Interpreter::checkMinimalPush()   D

Complexity

Conditions 9
Paths 8

Size

Total Lines 25
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 18
CRAP Score 9

Importance

Changes 0
Metric Value
cc 9
eloc 18
nc 8
nop 2
dl 0
loc 25
ccs 18
cts 18
cp 1
crap 9
rs 4.909
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 288
    public function __construct(EcAdapterInterface $ecAdapter = null)
56
    {
57 288
        $ecAdapter = $ecAdapter ?: Bitcoin::getEcAdapter();
58 288
        $this->math = $ecAdapter->getMath();
59 288
        $this->vchFalse = new Buffer("", 0, $this->math);
60 288
        $this->vchTrue = new Buffer("\x01", 1, $this->math);
61 288
    }
62
63
    /**
64
     * Cast the value to a boolean
65
     *
66
     * @param BufferInterface $value
67
     * @return bool
68
     */
69 1828
    public function castToBool(BufferInterface $value)
70
    {
71 1828
        $val = $value->getBinary();
72 1828
        for ($i = 0, $size = strlen($val); $i < $size; $i++) {
73 1674
            $chr = ord($val[$i]);
74 1674
            if ($chr !== 0) {
75 1668
                if (($i === ($size - 1)) && $chr === 0x80) {
76
                    return false;
77
                }
78 1668
                return true;
79
            }
80 5
        }
81 416
        return false;
82
    }
83
84
    /**
85
     * @param BufferInterface $signature
86
     * @return bool
87
     */
88 1
    public function isValidSignatureEncoding(BufferInterface $signature)
89 1
    {
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 382
    public function checkMinimalPush($opCode, BufferInterface $pushData)
107
    {
108 382
        $pushSize = $pushData->getSize();
109 382
        $binary = $pushData->getBinary();
110
111 382
        if ($pushSize === 0) {
112 148
            return $opCode === Opcodes::OP_0;
113 340
        } 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 13
                return $opCode === Opcodes::OP_1NEGATE;
120
            }
121 301
        } elseif ($pushSize <= 75) {
122 292
            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 2376
    private function checkOpcodeCount($count)
137
    {
138 2376
        if ($count > 201) {
139 10
            throw new \RuntimeException('Error: Script op code count');
140
        }
141
142 2376
        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 61
    private function verifyWitnessProgram(WitnessProgram $witnessProgram, ScriptWitnessInterface $scriptWitness, $flags, Checker $checker)
153
    {
154 60
        $witnessCount = count($scriptWitness);
155
156 60
        if ($witnessProgram->getVersion() === 0) {
157 58
            $buffer = $witnessProgram->getProgram();
158 58
            if ($buffer->getSize() === 32) {
159
                // Version 0 segregated witness program: SHA256(Script) in program, Script + inputs in witness
160 34
                if ($witnessCount === 0) {
161
                    // Must contain script at least
162 2
                    return false;
163
                }
164
165 32
                $scriptPubKey = new Script($scriptWitness[$witnessCount - 1]);
166 32
                $stackValues = $scriptWitness->slice(0, -1);
167 32
                $hashScriptPubKey = Hash::sha256($scriptPubKey->getBuffer());
168
169 32
                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 18
                    return false;
171
                }
172 38
            } elseif ($buffer->getSize() === 20) {
173
                // Version 0 special case for pay-to-pubkeyhash
174 22
                if ($witnessCount !== 2) {
175
                    // 2 items in witness - <signature> <pubkey>
176 13
                    return false;
177
                }
178
179 20
                $scriptPubKey = ScriptFactory::scriptPubKey()->payToPubKeyHash($buffer);
180 21
                $stackValues = $scriptWitness;
181 10
            } else {
182 26
                return false;
183
            }
184 26
        } elseif ($flags & self::VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM) {
185 2
            return false;
186
        } else {
187
            return false;
188
        }
189
190 48
        $mainStack = new Stack();
191 48
        foreach ($stackValues as $value) {
192 46
            $mainStack->push($value);
193 24
        }
194
195 48
        if (!$this->evaluate($scriptPubKey, $mainStack, SigHash::V1, $flags, $checker)) {
196 14
            return false;
197
        }
198
199 48
        if ($mainStack->count() !== 1) {
200
            return false;
201
        }
202
203 48
        if (!$this->castToBool($mainStack->bottom())) {
204 18
            return false;
205
        }
206
207 30
        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 2448
    public function verify(ScriptInterface $scriptSig, ScriptInterface $scriptPubKey, $flags, Checker $checker, ScriptWitnessInterface $witness = null)
219
    {
220 2448
        static $emptyWitness = null;
221 2448
        if ($emptyWitness === null) {
222 6
            $emptyWitness = new ScriptWitness([]);
223 3
        }
224
225 2448
        $witness = is_null($witness) ? $emptyWitness : $witness;
226
227 2448
        if (($flags & self::VERIFY_SIGPUSHONLY) !== 0 && !$scriptSig->isPushOnly()) {
228 4
            return false;
229
        }
230
231 2444
        $stack = new Stack();
232 2444
        if (!$this->evaluate($scriptSig, $stack, SigHash::V0, $flags, $checker)) {
233 116
            return false;
234
        }
235
236 2328
        $backup = [];
237 2328
        if ($flags & self::VERIFY_P2SH) {
238 1602
            foreach ($stack as $s) {
239 1302
                $backup[] = $s;
240 801
            }
241 801
        }
242
243 2328
        if (!$this->evaluate($scriptPubKey, $stack, SigHash::V0, $flags, $checker)) {
244 786
            return false;
245
        }
246
247 1566
        if ($stack->isEmpty()) {
248 26
            return false;
249
        }
250
251 1540
        if (false === $this->castToBool($stack[-1])) {
252 112
            return false;
253
        }
254
255 1428
        $program = null;
256 1428
        if ($flags & self::VERIFY_WITNESS) {
257 84
            if ($scriptPubKey->isWitness($program)) {
258
                /** @var WitnessProgram $program */
259 38
                if ($scriptSig->getBuffer()->getSize() !== 0) {
260 2
                    return false;
261
                }
262
263 36
                if (!$this->verifyWitnessProgram($program, $witness, $flags, $checker)) {
264 32
                    return false;
265
                }
266
267 14
                $stack->resize(1);
268 7
            }
269 30
        }
270
271 1404
        if ($flags & self::VERIFY_P2SH && (new OutputClassifier())->isPayToScriptHash($scriptPubKey)) {
272 86
            if (!$scriptSig->isPushOnly()) {
273 12
                return false;
274
            }
275
276 74
            $stack = new Stack();
277 74
            foreach ($backup as $i) {
278 74
                $stack->push($i);
279 37
            }
280
281
            // Restore mainStack to how it was after evaluating scriptSig
282 74
            if ($stack->isEmpty()) {
283
                return false;
284
            }
285
286
            // Load redeemscript as the scriptPubKey
287 74
            $scriptPubKey = new Script($stack->bottom());
288 74
            $stack->pop();
289
290 74
            if (!$this->evaluate($scriptPubKey, $stack, 0, $flags, $checker)) {
291 20
                return false;
292
            }
293
294 60
            if ($stack->isEmpty()) {
295
                return false;
296
            }
297
298 60
            if (!$this->castToBool($stack->bottom())) {
299 2
                return false;
300
            }
301
302 58
            if ($flags & self::VERIFY_WITNESS) {
303 32
                if ($scriptPubKey->isWitness($program)) {
304
                    /** @var WitnessProgram $program */
305 26
                    if (!$scriptSig->equals(ScriptFactory::sequence([$scriptPubKey->getBuffer()]))) {
306 2
                        return false; // SCRIPT_ERR_WITNESS_MALLEATED_P2SH
307
                    }
308
309 24
                    if (!$this->verifyWitnessProgram($program, $witness, $flags, $checker)) {
310 20
                        return false;
311
                    }
312
313 16
                    $stack->resize(1);
314 8
                }
315 11
            }
316 24
        }
317
318 1366
        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 10
        }
327
328 1362
        if ($flags & self::VERIFY_WITNESS) {
329 50
            if (!$flags & self::VERIFY_P2SH) {
330
                return false; //
331
            }
332
333 50
            if ($program === null && !$witness->isNull()) {
334 2
                return false; // SCRIPT_ERR_WITNESS_UNEXPECTED
335
            }
336 24
        }
337
338 1360
        return true;
339
    }
340
341
    /**
342
     * @param Stack $vfStack
343
     * @param bool $value
344
     * @return bool
345
     */
346 2514
    private function checkExec(Stack $vfStack, $value)
347
    {
348 2514
        $ret = 0;
349 2514
        foreach ($vfStack as $item) {
350 484
            if ($item === $value) {
351 400
                $ret++;
352 158
            }
353 1257
        }
354
355 2514
        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 2528
    public function evaluate(ScriptInterface $script, Stack $mainStack, $sigVersion, $flags, Checker $checker)
367
    {
368 2528
        $hashStartPos = 0;
369 2528
        $opCount = 0;
370 2528
        $zero = gmp_init(0, 10);
371 2528
        $altStack = new Stack();
372 2528
        $vfStack = new Stack();
373 2528
        $minimal = ($flags & self::VERIFY_MINIMALDATA) !== 0;
374 2528
        $parser = $script->getScriptParser();
375
376 2528
        if ($script->getBuffer()->getSize() > 10000) {
377 2
            return false;
378
        }
379
380
        try {
381 2528
            foreach ($parser as $operation) {
382 2514
                $opCode = $operation->getOp();
383 2514
                $pushData = $operation->getData();
384 2514
                $fExec = !$this->checkExec($vfStack, false);
385
386
                // If pushdata was written to
387 2514
                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 2508
                if ($opCode > Opcodes::OP_16 && ++$opCount) {
393 2376
                    $this->checkOpcodeCount($opCount);
394 1188
                }
395
396 2508
                if (in_array($opCode, $this->disabledOps, true)) {
397 48
                    throw new \RuntimeException('Disabled Opcode');
398
                }
399
400 2508
                if ($fExec && $operation->isPush()) {
401
                    // In range of a pushdata opcode
402 1908
                    if ($minimal && !$this->checkMinimalPush($opCode, $pushData)) {
403 42
                        throw new ScriptRuntimeException(self::VERIFY_MINIMALDATA, 'Minimal pushdata required');
404
                    }
405
406 1866
                    $mainStack->push($pushData);
407
                    // echo " - [pushed '" . $pushData->getHex() . "']\n";
408 2444
                } elseif ($fExec || (Opcodes::OP_IF <= $opCode && $opCode <= Opcodes::OP_ENDIF)) {
409
                    // echo "OPCODE - " . $script->getOpcodes()->getOp($opCode) . "\n";
410
                    switch ($opCode) {
411 2422
                        case Opcodes::OP_1NEGATE:
412 2422
                        case Opcodes::OP_1:
413 2400
                        case Opcodes::OP_2:
414 2396
                        case Opcodes::OP_3:
415 2396
                        case Opcodes::OP_4:
416 2396
                        case Opcodes::OP_5:
417 2396
                        case Opcodes::OP_6:
418 2396
                        case Opcodes::OP_7:
419 2395
                        case Opcodes::OP_8:
420 2395
                        case Opcodes::OP_9:
421 2395
                        case Opcodes::OP_10:
422 2395
                        case Opcodes::OP_11:
423 2394
                        case Opcodes::OP_12:
424 2394
                        case Opcodes::OP_13:
425 2394
                        case Opcodes::OP_14:
426 2394
                        case Opcodes::OP_15:
427 2394
                        case Opcodes::OP_16:
428 1360
                            $num = \BitWasp\Bitcoin\Script\decodeOpN($opCode);
429 1360
                            $mainStack->push(Number::int($num)->getBuffer());
430 1360
                            break;
431
432 2366
                        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 2364
                        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 2350
                        case Opcodes::OP_NOP1:
479 2349
                        case Opcodes::OP_NOP4:
480 2348
                        case Opcodes::OP_NOP5:
481 2347
                        case Opcodes::OP_NOP6:
482 2346
                        case Opcodes::OP_NOP7:
483 2345
                        case Opcodes::OP_NOP8:
484 2344
                        case Opcodes::OP_NOP9:
485 2343
                        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 2330
                        case Opcodes::OP_NOP:
492 168
                            break;
493
494 2284
                        case Opcodes::OP_IF:
495 2262
                        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 17
                                }
508 245
                            }
509 490
                            $vfStack->push($value);
510 490
                            break;
511
512 2236
                        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 2230
                        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 1958
                        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 1944
                        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 1940
                        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 1934
                        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 3
                            }
560 8
                            break;
561
562 1928
                        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 1910
                        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 1904
                        case Opcodes::OP_DUP:
576 164
                            if ($mainStack->isEmpty()) {
577 28
                                throw new \RuntimeException('Invalid stack operation OP_DUP');
578
                            }
579 160
                            $vch = $mainStack[-1];
580 160
                            $mainStack->push($vch);
581 160
                            break;
582
583 1886
                        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 1874
                        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 1866
                        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 1854
                        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 1846
                        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 1838
                        case Opcodes::OP_PICK:
622 1829
                        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 9
                            }
638 36
                            $mainStack->push($vch);
639 36
                            break;
640
641 1804
                        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 1800
                        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 1792
                        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 1772
                        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 1764
                        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 1760
                        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 1752
                        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 1746
                        case Opcodes::OP_EQUAL:
709 1635
                        case Opcodes::OP_EQUALVERIFY:
710 742
                            if (count($mainStack) < 2) {
711 8
                                throw new \RuntimeException('Invalid stack operation OP_EQUAL');
712
                            }
713
714 734
                            $equal = $mainStack[-2]->equals($mainStack[-1]);
715 734
                            $mainStack->pop();
716 734
                            $mainStack->pop();
717 734
                            $mainStack->push($equal ? $this->vchTrue : $this->vchFalse);
718 734
                            if ($opCode === Opcodes::OP_EQUALVERIFY) {
719 198
                                if ($equal) {
720 174
                                    $mainStack->pop();
721 87
                                } else {
722 24
                                    throw new \RuntimeException('Error EQUALVERIFY');
723
                                }
724 87
                            }
725
726 712
                            break;
727
728
                        // Arithmetic operations
729 1462
                        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 151
                            } elseif ($opCode === Opcodes::OP_1SUB) {
739 6
                                $num = $this->math->sub($num, gmp_init(1));
740 141
                            } 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 135
                            } elseif ($opCode === Opcodes::OP_ABS) {
745 10
                                if ($this->math->cmp($num, $zero) < 0) {
746 7
                                    $num = $this->math->sub($zero, $num);
747 2
                                }
748 127
                            } elseif ($opCode === Opcodes::OP_NOT) {
749 110
                                $num = gmp_init($this->math->cmp($num, $zero) === 0 ? 1 : 0);
750 55
                            } 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 1344
                        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 218
                            } else if ($opCode === Opcodes::OP_SUB) {
773 12
                                $num = $this->math->sub($num1, $num2);
774 188
                            } else if ($opCode === Opcodes::OP_BOOLAND) {
775 16
                                $num = $this->math->cmp($num1, $zero) !== 0 && $this->math->cmp($num2, $zero) !== 0;
776 174
                            } else if ($opCode === Opcodes::OP_BOOLOR) {
777 16
                                $num = $this->math->cmp($num1, $zero) !== 0 || $this->math->cmp($num2, $zero) !== 0;
778 158
                            } elseif ($opCode === Opcodes::OP_NUMEQUAL) {
779 56
                                $num = $this->math->cmp($num1, $num2) === 0;
780 130
                            } elseif ($opCode === Opcodes::OP_NUMEQUALVERIFY) {
781 8
                                $num = $this->math->cmp($num1, $num2) === 0;
782 106
                            } elseif ($opCode === Opcodes::OP_NUMNOTEQUAL) {
783 10
                                $num = $this->math->cmp($num1, $num2) !== 0;
784 97
                            } elseif ($opCode === Opcodes::OP_LESSTHAN) {
785 16
                                $num = $this->math->cmp($num1, $num2) < 0;
786 84
                            } elseif ($opCode === Opcodes::OP_GREATERTHAN) {
787 16
                                $num = $this->math->cmp($num1, $num2) > 0;
788 68
                            } elseif ($opCode === Opcodes::OP_LESSTHANOREQUAL) {
789 16
                                $num = $this->math->cmp($num1, $num2) <= 0;
790 52
                            } elseif ($opCode === Opcodes::OP_GREATERTHANOREQUAL) {
791 16
                                $num = $this->math->cmp($num1, $num2) >= 0;
792 36
                            } elseif ($opCode === Opcodes::OP_MIN) {
793 14
                                $num = ($this->math->cmp($num1, $num2) <= 0) ? $num1 : $num2;
794 7
                            } 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 4
                                } else {
807
                                    throw new \RuntimeException('NUM EQUAL VERIFY error');
808
                                }
809 4
                            }
810 242
                            break;
811
812 1016
                        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 986
                        case Opcodes::OP_RIPEMD160:
830 980
                        case Opcodes::OP_SHA1:
831 972
                        case Opcodes::OP_SHA256:
832 966
                        case Opcodes::OP_HASH160:
833 915
                        case Opcodes::OP_HASH256:
834 326
                            if ($mainStack->isEmpty()) {
835 26
                                throw new \RuntimeException('Invalid stack operation');
836
                            }
837
838 300
                            $buffer = $mainStack[-1];
839 300
                            if ($opCode === Opcodes::OP_RIPEMD160) {
840 10
                                $hash = Hash::ripemd160($buffer);
841 296
                            } elseif ($opCode === Opcodes::OP_SHA1) {
842 12
                                $hash = Hash::sha1($buffer);
843 286
                            } elseif ($opCode === Opcodes::OP_SHA256) {
844 12
                                $hash = Hash::sha256($buffer);
845 276
                            } elseif ($opCode === Opcodes::OP_HASH160) {
846 262
                                $hash = Hash::sha256ripe160($buffer);
847 131
                            } else {
848 10
                                $hash = Hash::sha256d($buffer);
849
                            }
850
851 300
                            $mainStack->pop();
852 300
                            $mainStack->push($hash);
853 300
                            break;
854
855 830
                        case Opcodes::OP_CODESEPARATOR:
856 2
                            $hashStartPos = $parser->getPosition();
857 2
                            break;
858
859 828
                        case Opcodes::OP_CHECKSIG:
860 638
                        case Opcodes::OP_CHECKSIGVERIFY:
861 380
                            if (count($mainStack) < 2) {
862 14
                                throw new \RuntimeException('Invalid stack operation');
863
                            }
864
865 376
                            $vchPubKey = $mainStack[-1];
866 376
                            $vchSig = $mainStack[-2];
867
868 376
                            $scriptCode = new Script($script->getBuffer()->slice($hashStartPos));
869
870 376
                            $success = $checker->checkSig($scriptCode, $vchSig, $vchPubKey, $sigVersion, $flags);
871
872 256
                            $mainStack->pop();
873 256
                            $mainStack->pop();
874 256
                            $mainStack->push($success ? $this->vchTrue : $this->vchFalse);
875
876 256
                            if ($opCode === Opcodes::OP_CHECKSIGVERIFY) {
877
                                if ($success) {
878
                                    $mainStack->pop();
879
                                } else {
880
                                    throw new \RuntimeException('Checksig verify');
881
                                }
882
                            }
883 256
                            break;
884
885 448
                        case Opcodes::OP_CHECKMULTISIG:
886 356
                        case Opcodes::OP_CHECKMULTISIGVERIFY:
887 248
                            $i = 1;
888 248
                            if (count($mainStack) < $i) {
889 2
                                throw new \RuntimeException('Invalid stack operation');
890
                            }
891
892 246
                            $keyCount = Number::buffer($mainStack[-$i], $minimal)->getInt();
893 242
                            if ($keyCount < 0 || $keyCount > 20) {
894 4
                                throw new \RuntimeException('OP_CHECKMULTISIG: Public key count exceeds 20');
895
                            }
896
897 238
                            $opCount += $keyCount;
898 238
                            $this->checkOpcodeCount($opCount);
899
900
                            // Extract positions of the keys, and signatures, from the stack.
901 238
                            $ikey = ++$i;
902 238
                            $i += $keyCount;
903 238
                            if (count($mainStack) < $i) {
904 2
                                throw new \RuntimeException('Invalid stack operation');
905
                            }
906
907 236
                            $sigCount = Number::buffer($mainStack[-$i], $minimal)->getInt();
908 230
                            if ($sigCount < 0 || $sigCount > $keyCount) {
909 4
                                throw new \RuntimeException('Invalid Signature count');
910
                            }
911
912 226
                            $isig = ++$i;
913 226
                            $i += $sigCount;
914
915
                            // Extract the script since the last OP_CODESEPARATOR
916 226
                            $scriptCode = new Script($script->getBuffer()->slice($hashStartPos));
917
918 226
                            $fSuccess = true;
919 226
                            while ($fSuccess && $sigCount > 0) {
920
                                // Fetch the signature and public key
921 106
                                $sig = $mainStack[-$isig];
922 104
                                $pubkey = $mainStack[-$ikey];
923
924 104
                                if ($checker->checkSig($scriptCode, $sig, $pubkey, $sigVersion, $flags)) {
925 52
                                    $isig++;
926 52
                                    $sigCount--;
927 26
                                }
928
929 84
                                $ikey++;
930 84
                                $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 84
                                if ($sigCount > $keyCount) {
936 46
                                    $fSuccess = false;
937 23
                                }
938 42
                            }
939
940 192
                            while ($i-- > 1) {
941 192
                                $mainStack->pop();
942 96
                            }
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 192
                            if ($mainStack->isEmpty()) {
951 10
                                throw new \RuntimeException('Invalid stack operation');
952
                            }
953
954 192
                            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 188
                            $mainStack->pop();
959 188
                            $mainStack->push($fSuccess ? $this->vchTrue : $this->vchFalse);
960
961 188
                            if ($opCode === Opcodes::OP_CHECKMULTISIGVERIFY) {
962 60
                                if ($fSuccess) {
963 60
                                    $mainStack->pop();
964 30
                                } else {
965
                                    throw new \RuntimeException('OP_CHECKMULTISIG verify');
966
                                }
967 30
                            }
968 188
                            break;
969
970 100
                        default:
971 200
                            throw new \RuntimeException('Opcode not found');
972 100
                    }
973
974 2140
                    if (count($mainStack) + count($altStack) > 1000) {
975 1220
                        throw new \RuntimeException('Invalid stack size, exceeds 1000');
976
                    }
977 1070
                }
978 1232
            }
979
980 2422
            if (count($vfStack) !== 0) {
981 12
                throw new \RuntimeException('Unbalanced conditional at script end');
982
            }
983
984 2412
            return true;
985 946
        } 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 718
        } catch (\Exception $e) {
990
            // echo "\n General: " . $e->getMessage()  . PHP_EOL . $e->getTraceAsString() . PHP_EOL;
991 718
            return false;
992
        }
993
    }
994
}
995