Completed
Pull Request — master (#524)
by thomas
40:24 queued 38:13
created

Interpreter::evaluate()   F

Complexity

Conditions 204
Paths 5300

Size

Total Lines 653
Code Lines 445

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 424
CRAP Score 204.6739

Importance

Changes 0
Metric Value
cc 204
eloc 445
nc 5300
nop 5
dl 0
loc 653
ccs 424
cts 435
cp 0.9747
crap 204.6739
rs 2
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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