Completed
Pull Request — master (#403)
by thomas
75:49 queued 72:57
created

Interpreter::verifyWitnessProgram()   C

Complexity

Conditions 12
Paths 22

Size

Total Lines 57
Code Lines 33

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 30
CRAP Score 12.1081

Importance

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