Completed
Push — master ( 8ee677...9f7fbd )
by thomas
74:58 queued 72:17
created

Interpreter::verify()   F

Complexity

Conditions 35
Paths 1176

Size

Total Lines 122
Code Lines 62

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 69
CRAP Score 35.2015

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 35
eloc 62
c 1
b 0
f 0
nc 1176
nop 5
dl 0
loc 122
ccs 69
cts 73
cp 0.9452
crap 35.2015
rs 2

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