Completed
Pull Request — master (#449)
by thomas
119:48 queued 116:58
created

Interpreter::verify()   F

Complexity

Conditions 35
Paths 1176

Size

Total Lines 122
Code Lines 62

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 59
CRAP Score 35.1388

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 35
eloc 62
nc 1176
nop 5
dl 0
loc 122
ccs 59
cts 62
cp 0.9516
crap 35.1388
rs 2
c 1
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

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

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

Commonly applied refactorings include:

1
<?php
2
3
namespace BitWasp\Bitcoin\Script\Interpreter;
4
5
use BitWasp\Bitcoin\Bitcoin;
6
use BitWasp\Bitcoin\Crypto\EcAdapter\Adapter\EcAdapterInterface;
7
use BitWasp\Bitcoin\Crypto\Hash;
8
use BitWasp\Bitcoin\Exceptions\ScriptRuntimeException;
9
use BitWasp\Bitcoin\Exceptions\SignatureNotCanonical;
10
use BitWasp\Bitcoin\Script\Classifier\OutputClassifier;
11
use BitWasp\Bitcoin\Script\Opcodes;
12
use BitWasp\Bitcoin\Script\Script;
13
use BitWasp\Bitcoin\Script\ScriptFactory;
14
use BitWasp\Bitcoin\Script\ScriptInterface;
15
use BitWasp\Bitcoin\Script\ScriptWitness;
16
use BitWasp\Bitcoin\Script\ScriptWitnessInterface;
17
use BitWasp\Bitcoin\Script\WitnessProgram;
18
use BitWasp\Bitcoin\Signature\TransactionSignature;
19
use BitWasp\Bitcoin\Transaction\SignatureHash\SigHash;
20
use BitWasp\Bitcoin\Transaction\TransactionInputInterface;
21
use BitWasp\Buffertools\Buffer;
22
use BitWasp\Buffertools\BufferInterface;
23
24
class Interpreter implements InterpreterInterface
25
{
26
27
    /**
28
     * @var \BitWasp\Bitcoin\Math\Math
29
     */
30
    private $math;
31
32
    /**
33
     * @var BufferInterface
34
     */
35
    private $vchFalse;
36
37
    /**
38
     * @var BufferInterface
39
     */
40
    private $vchTrue;
41
42
    /**
43
     * @var array
44
     */
45
    private $disabledOps = [
46
        Opcodes::OP_CAT,    Opcodes::OP_SUBSTR, Opcodes::OP_LEFT,  Opcodes::OP_RIGHT,
47
        Opcodes::OP_INVERT, Opcodes::OP_AND,    Opcodes::OP_OR,    Opcodes::OP_XOR,
48
        Opcodes::OP_2MUL,   Opcodes::OP_2DIV,   Opcodes::OP_MUL,   Opcodes::OP_DIV,
49
        Opcodes::OP_MOD,    Opcodes::OP_LSHIFT, Opcodes::OP_RSHIFT
50
    ];
51
52
    /**
53
     * @param EcAdapterInterface $ecAdapter
54
     */
55 104
    public function __construct(EcAdapterInterface $ecAdapter = null)
56
    {
57 104
        $ecAdapter = $ecAdapter ?: Bitcoin::getEcAdapter();
58 104
        $this->math = $ecAdapter->getMath();
59 104
        $this->vchFalse = new Buffer("", 0, $this->math);
60 104
        $this->vchTrue = new Buffer("\x01", 1, $this->math);
61 104
    }
62
63
    /**
64
     * Cast the value to a boolean
65
     *
66
     * @param BufferInterface $value
67
     * @return bool
68
     */
69 953
    public function castToBool(BufferInterface $value)
70
    {
71 953
        $val = $value->getBinary();
72 953
        for ($i = 0, $size = strlen($val); $i < $size; $i++) {
73 878
            $chr = ord($val[$i]);
74 878
            if ($chr !== 0) {
75 876
                if (($i === ($size - 1)) && $chr === 0x80) {
76
                    return false;
77
                }
78 876
                return true;
79
            }
80
        }
81 223
        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 167
    public function checkMinimalPush($opCode, BufferInterface $pushData)
107
    {
108 167
        $pushSize = $pushData->getSize();
109 167
        $binary = $pushData->getBinary();
110
111 167
        if ($pushSize === 0) {
112 82
            return $opCode === Opcodes::OP_0;
113 146
        } elseif ($pushSize === 1) {
114 24
            $first = ord($binary[0]);
115
116 24
            if ($first >= 1 && $first <= 16) {
117 18
                return $opCode === (Opcodes::OP_1 + ($first - 1));
118 8
            } elseif ($first === 0x81) {
119 8
                return $opCode === Opcodes::OP_1NEGATE;
120
            }
121 124
        } elseif ($pushSize <= 75) {
122 122
            return $opCode === $pushSize;
123 4
        } elseif ($pushSize <= 255) {
124 3
            return $opCode === Opcodes::OP_PUSHDATA1;
125 3
        } elseif ($pushSize <= 65535) {
126 3
            return $opCode === Opcodes::OP_PUSHDATA2;
127
        }
128
129 7
        return true;
130
    }
131
132
    /**
133
     * @param int $count
134
     * @return $this
135
     */
136 1210
    private function checkOpcodeCount($count)
137
    {
138 1210
        if ($count > 201) {
139 5
            throw new \RuntimeException('Error: Script op code count');
140
        }
141
142 1210
        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 87
    private function verifyWitnessProgram(WitnessProgram $witnessProgram, ScriptWitnessInterface $scriptWitness, $flags, Checker $checker)
153
    {
154 87
        $witnessCount = count($scriptWitness);
155
156 87
        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 72
                if ($witnessCount === 0) {
161
                    // Must contain script at least
162 1
                    return false;
163
                }
164
165 71
                $scriptPubKey = new Script($scriptWitness[$witnessCount - 1]);
166 71
                $stackValues = $scriptWitness->slice(0, -1);
167 71
                if (!$buffer->equals($scriptPubKey->getWitnessScriptHash())) {
0 ignored issues
show
Documentation introduced by
$scriptPubKey->getWitnessScriptHash() 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...
168 71
                    return false;
169
                }
170 15
            } elseif ($buffer->getSize() === 20) {
171
                // Version 0 special case for pay-to-pubkeyhash
172 15
                if ($witnessCount !== 2) {
173
                    // 2 items in witness - <signature> <pubkey>
174 9
                    return false;
175
                }
176
177 14
                $scriptPubKey = ScriptFactory::scriptPubKey()->payToPubKeyHash($buffer);
178 14
                $stackValues = $scriptWitness;
179
            } else {
180 83
                return false;
181
            }
182
        } elseif ($flags & self::VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM) {
183
            return false;
184
        } else {
185
            return false;
186
        }
187
188 83
        $mainStack = new Stack();
189 83
        foreach ($stackValues as $value) {
190 74
            $mainStack->push($value);
191
        }
192
193 83
        if (!$this->evaluate($scriptPubKey, $mainStack, SigHash::V1, $flags, $checker)) {
194 34
            return false;
195
        }
196
197 63
        if ($mainStack->count() !== 1) {
198 14
            return false;
199
        }
200
201 49
        if (!$this->castToBool($mainStack->bottom())) {
202 9
            return false;
203
        }
204
205 40
        return true;
206
    }
207
208
    /**
209
     * @param ScriptInterface $scriptSig
210
     * @param ScriptInterface $scriptPubKey
211
     * @param int $flags
212
     * @param Checker $checker
213
     * @param ScriptWitnessInterface|null $witness
214
     * @return bool
215
     */
216 1274
    public function verify(ScriptInterface $scriptSig, ScriptInterface $scriptPubKey, $flags, Checker $checker, ScriptWitnessInterface $witness = null)
217
    {
218 1274
        static $emptyWitness = null;
219 1274
        if ($emptyWitness === null) {
220 2
            $emptyWitness = new ScriptWitness([]);
221
        }
222
223 1274
        $witness = is_null($witness) ? $emptyWitness : $witness;
224
225 1274
        if (($flags & self::VERIFY_SIGPUSHONLY) !== 0 && !$scriptSig->isPushOnly()) {
226 2
            return false;
227
        }
228
229 1272
        $stack = new Stack();
230 1272
        if (!$this->evaluate($scriptSig, $stack, SigHash::V0, $flags, $checker)) {
231 57
            return false;
232
        }
233
234 1215
        $backup = [];
235 1215
        if ($flags & self::VERIFY_P2SH) {
236 884
            foreach ($stack as $s) {
237 707
                $backup[] = $s;
238
            }
239
        }
240
241 1215
        if (!$this->evaluate($scriptPubKey, $stack, SigHash::V0, $flags, $checker)) {
242 389
            return false;
243
        }
244
245 850
        if ($stack->isEmpty()) {
246 17
            return false;
247
        }
248
249 833
        if (false === $this->castToBool($stack[-1])) {
250 52
            return false;
251
        }
252
253 781
        $program = null;
254 781
        if ($flags & self::VERIFY_WITNESS) {
255 109
            if ($scriptPubKey->isWitness($program)) {
256
                /** @var WitnessProgram $program */
257 46
                if ($scriptSig->getBuffer()->getSize() !== 0) {
258 1
                    return false;
259
                }
260
261 45
                if (!$this->verifyWitnessProgram($program, $witness, $flags, $checker)) {
262 36
                    return false;
263
                }
264
265 19
                $stack->resize(1);
266
            }
267
        }
268
269 752
        if ($flags & self::VERIFY_P2SH && (new OutputClassifier())->isPayToScriptHash($scriptPubKey)) {
270 83
            if (!$scriptSig->isPushOnly()) {
271 5
                return false;
272
            }
273
274 78
            $stack = new Stack();
275 78
            foreach ($backup as $i) {
276 78
                $stack->push($i);
277
            }
278
279
            // Restore mainStack to how it was after evaluating scriptSig
280 78
            if ($stack->isEmpty()) {
281
                return false;
282
            }
283
284
            // Load redeemscript as the scriptPubKey
285 78
            $scriptPubKey = new Script($stack->bottom());
286 78
            $stack->pop();
287
288 78
            if (!$this->evaluate($scriptPubKey, $stack, 0, $flags, $checker)) {
289 14
                return false;
290
            }
291
292 70
            if ($stack->isEmpty()) {
293 5
                return false;
294
            }
295
296 65
            if (!$this->castToBool($stack->bottom())) {
297 1
                return false;
298
            }
299
300 64
            if ($flags & self::VERIFY_WITNESS) {
301 48
                if ($scriptPubKey->isWitness($program)) {
302
                    /** @var WitnessProgram $program */
303 43
                    if (!$scriptSig->equals(ScriptFactory::sequence([$scriptPubKey->getBuffer()]))) {
304 1
                        return false; // SCRIPT_ERR_WITNESS_MALLEATED_P2SH
305
                    }
306
307 42
                    if (!$this->verifyWitnessProgram($program, $witness, $flags, $checker)) {
308 33
                        return false;
309
                    }
310
311 21
                    $stack->resize(1);
312
                }
313
            }
314
        }
315
316 711
        if ($flags & self::VERIFY_CLEAN_STACK) {
317 3
            if (!($flags & self::VERIFY_P2SH !== 0) && ($flags & self::VERIFY_WITNESS !== 0)) {
318
                return false; // implied flags required
319
            }
320
321 3
            if (count($stack) !== 1) {
322 2
                return false; // Cleanstack
323
            }
324
        }
325
326 709
        if ($flags & self::VERIFY_WITNESS) {
327 51
            if (!$flags & self::VERIFY_P2SH) {
328
                return false; //
329
            }
330
331 51
            if ($program === null && !$witness->isNull()) {
332 1
                return false; // SCRIPT_ERR_WITNESS_UNEXPECTED
333
            }
334
        }
335
336 708
        return true;
337
    }
338
339
    /**
340
     * @param Stack $vfStack
341
     * @param bool $value
342
     * @return bool
343
     */
344 1276
    private function checkExec(Stack $vfStack, $value)
345
    {
346 1276
        $ret = 0;
347 1276
        foreach ($vfStack as $item) {
348 290
            if ($item === $value) {
349 290
                $ret++;
350
            }
351
        }
352
353 1276
        return $ret;
354
    }
355
356
    /**
357
     * @param ScriptInterface $script
358
     * @param Stack $mainStack
359
     * @param int $sigVersion
360
     * @param int $flags
361
     * @param Checker $checker
362
     * @return bool
363
     */
364 1292
    public function evaluate(ScriptInterface $script, Stack $mainStack, $sigVersion, $flags, Checker $checker)
365
    {
366 1292
        $hashStartPos = 0;
367 1292
        $opCount = 0;
368 1292
        $zero = gmp_init(0, 10);
369 1292
        $altStack = new Stack();
370 1292
        $vfStack = new Stack();
371 1292
        $minimal = ($flags & self::VERIFY_MINIMALDATA) !== 0;
372 1292
        $parser = $script->getScriptParser();
373
374 1292
        if ($script->getBuffer()->getSize() > 10000) {
375 1
            return false;
376
        }
377
378
        try {
379 1292
            foreach ($parser as $operation) {
380 1276
                $opCode = $operation->getOp();
381 1276
                $pushData = $operation->getData();
382 1276
                $fExec = !$this->checkExec($vfStack, false);
383
384
                // If pushdata was written to
385 1276
                if ($operation->isPush() && $operation->getDataSize() > InterpreterInterface::MAX_SCRIPT_ELEMENT_SIZE) {
386 4
                    throw new \RuntimeException('Error - push size');
387
                }
388
389
                // OP_RESERVED should not count towards opCount
390 1274
                if ($opCode > Opcodes::OP_16 && ++$opCount) {
391 1210
                    $this->checkOpcodeCount($opCount);
392
                }
393
394 1274
                if (in_array($opCode, $this->disabledOps, true)) {
395 24
                    throw new \RuntimeException('Disabled Opcode');
396
                }
397
398 1274
                if ($fExec && $operation->isPush()) {
399
                    // In range of a pushdata opcode
400 972
                    if ($minimal && !$this->checkMinimalPush($opCode, $pushData)) {
401 21
                        throw new ScriptRuntimeException(self::VERIFY_MINIMALDATA, 'Minimal pushdata required');
402
                    }
403
404 951
                    $mainStack->push($pushData);
405
                    // echo " - [pushed '" . $pushData->getHex() . "']\n";
406 1233
                } elseif ($fExec || (Opcodes::OP_IF <= $opCode && $opCode <= Opcodes::OP_ENDIF)) {
407
                    // echo "OPCODE - " . $script->getOpcodes()->getOp($opCode) . "\n";
408
                    switch ($opCode) {
409 1233
                        case Opcodes::OP_1NEGATE:
410 1233
                        case Opcodes::OP_1:
411 1211
                        case Opcodes::OP_2:
412 1207
                        case Opcodes::OP_3:
413 1207
                        case Opcodes::OP_4:
414 1207
                        case Opcodes::OP_5:
415 1207
                        case Opcodes::OP_6:
416 1207
                        case Opcodes::OP_7:
417 1206
                        case Opcodes::OP_8:
418 1206
                        case Opcodes::OP_9:
419 1206
                        case Opcodes::OP_10:
420 1206
                        case Opcodes::OP_11:
421 1205
                        case Opcodes::OP_12:
422 1205
                        case Opcodes::OP_13:
423 1205
                        case Opcodes::OP_14:
424 1205
                        case Opcodes::OP_15:
425 1205
                        case Opcodes::OP_16:
426 718
                            $num = \BitWasp\Bitcoin\Script\decodeOpN($opCode);
427 718
                            $mainStack->push(Number::int($num)->getBuffer());
428 718
                            break;
429
430 1205
                        case Opcodes::OP_CHECKLOCKTIMEVERIFY:
431 6
                            if (!($flags & self::VERIFY_CHECKLOCKTIMEVERIFY)) {
432 6
                                if ($flags & self::VERIFY_DISCOURAGE_UPGRADABLE_NOPS) {
433 1
                                    throw new ScriptRuntimeException(self::VERIFY_DISCOURAGE_UPGRADABLE_NOPS, 'Upgradable NOP found - this is discouraged');
434
                                }
435 5
                                break;
436
                            }
437
438
                            if ($mainStack->isEmpty()) {
439
                                throw new \RuntimeException('Invalid stack operation - CLTV');
440
                            }
441
442
                            $lockTime = Number::buffer($mainStack[-1], $minimal, 5, $this->math);
443
                            if (!$checker->checkLockTime($lockTime)) {
444
                                throw new ScriptRuntimeException(self::VERIFY_CHECKLOCKTIMEVERIFY, 'Unsatisfied locktime');
445
                            }
446
447
                            break;
448
449 1204
                        case Opcodes::OP_CHECKSEQUENCEVERIFY:
450 12
                            if (!($flags & self::VERIFY_CHECKSEQUENCEVERIFY)) {
451 6
                                if ($flags & self::VERIFY_DISCOURAGE_UPGRADABLE_NOPS) {
452 1
                                    throw new ScriptRuntimeException(self::VERIFY_DISCOURAGE_UPGRADABLE_NOPS, 'Upgradable NOP found - this is discouraged');
453
                                }
454 5
                                break;
455
                            }
456
457 6
                            if ($mainStack->isEmpty()) {
458 1
                                throw new \RuntimeException('Invalid stack operation - CSV');
459
                            }
460
461 5
                            $sequence = Number::buffer($mainStack[-1], $minimal, 5, $this->math);
462 4
                            $nSequence = $sequence->getGmp();
463 4
                            if ($this->math->cmp($nSequence, $zero) < 0) {
464 1
                                throw new ScriptRuntimeException(self::VERIFY_CHECKSEQUENCEVERIFY, 'Negative locktime');
465
                            }
466
467 3
                            if ($this->math->cmp($this->math->bitwiseAnd($nSequence, gmp_init(TransactionInputInterface::SEQUENCE_LOCKTIME_DISABLE_FLAG, 10)), $zero) !== 0) {
468 1
                                break;
469
                            }
470
471 2
                            if (!$checker->checkSequence($sequence)) {
472 2
                                throw new ScriptRuntimeException(self::VERIFY_CHECKSEQUENCEVERIFY, 'Unsatisfied sequence');
473
                            }
474
                            break;
475
476 1197
                        case Opcodes::OP_NOP1:
477 1196
                        case Opcodes::OP_NOP4:
478 1195
                        case Opcodes::OP_NOP5:
479 1194
                        case Opcodes::OP_NOP6:
480 1193
                        case Opcodes::OP_NOP7:
481 1192
                        case Opcodes::OP_NOP8:
482 1191
                        case Opcodes::OP_NOP9:
483 1190
                        case Opcodes::OP_NOP10:
484 27
                            if ($flags & self::VERIFY_DISCOURAGE_UPGRADABLE_NOPS) {
485 10
                                throw new ScriptRuntimeException(self::VERIFY_DISCOURAGE_UPGRADABLE_NOPS, 'Upgradable NOP found - this is discouraged');
486
                            }
487 17
                            break;
488
489 1187
                        case Opcodes::OP_NOP:
490 84
                            break;
491
492 1164
                        case Opcodes::OP_IF:
493 1137
                        case Opcodes::OP_NOTIF:
494
                            // <expression> if [statements] [else [statements]] endif
495 317
                            $value = false;
496 317
                            if ($fExec) {
497 317
                                if ($mainStack->isEmpty()) {
498 12
                                    throw new \RuntimeException('Unbalanced conditional');
499
                                }
500 305
                                $vch = $mainStack[-1];
501
502 305
                                if ($sigVersion === SigHash::V1 && ($flags & self::VERIFY_MINIMALIF)) {
503 20
                                    if ($vch->getSize() > 1) {
504 4
                                        throw new ScriptRuntimeException(self::VERIFY_MINIMALIF, 'Input to OP_IF/NOTIF should be minimally encoded');
505
                                    }
506
507 16
                                    if ($vch->getSize() === 1 && $vch->getBinary() !== "\x01") {
508 8
                                        throw new ScriptRuntimeException(self::VERIFY_MINIMALIF, 'Input to OP_IF/NOTIF should be minimally encoded');
509
                                    }
510
                                }
511
512 293
                                $buffer = Number::buffer($mainStack->pop(), $minimal)->getBuffer();
0 ignored issues
show
Bug introduced by
It seems like $mainStack->pop() can be null; however, buffer() does not accept null, maybe add an additional type check?

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

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

function doesNotAcceptNull(stdClass $x) { }

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

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

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
513 293
                                $value = $this->castToBool($buffer);
514 293
                                if ($opCode === Opcodes::OP_NOTIF) {
515 41
                                    $value = !$value;
516
                                }
517
                            }
518 293
                            $vfStack->push($value);
519 293
                            break;
520
521 1130
                        case Opcodes::OP_ELSE:
522 115
                            if ($vfStack->isEmpty()) {
523 4
                                throw new \RuntimeException('Unbalanced conditional');
524
                            }
525 113
                            $vfStack->push(!$vfStack->pop());
526 113
                            break;
527
528 1127
                        case Opcodes::OP_ENDIF:
529 195
                            if ($vfStack->isEmpty()) {
530 7
                                throw new \RuntimeException('Unbalanced conditional');
531
                            }
532 191
                            $vfStack->pop();
533 191
                            break;
534
535 967
                        case Opcodes::OP_VERIFY:
536 30
                            if ($mainStack->isEmpty()) {
537 1
                                throw new \RuntimeException('Invalid stack operation');
538
                            }
539 29
                            $value = $this->castToBool($mainStack[-1]);
540 29
                            if (!$value) {
541 1
                                throw new \RuntimeException('Error: verify');
542
                            }
543 28
                            $mainStack->pop();
544 28
                            break;
545
546 960
                        case Opcodes::OP_TOALTSTACK:
547 8
                            if ($mainStack->isEmpty()) {
548 1
                                throw new \RuntimeException('Invalid stack operation OP_TOALTSTACK');
549
                            }
550 7
                            $altStack->push($mainStack->pop());
551 7
                            break;
552
553 958
                        case Opcodes::OP_FROMALTSTACK:
554 5
                            if ($altStack->isEmpty()) {
555 2
                                throw new \RuntimeException('Invalid alt-stack operation OP_FROMALTSTACK');
556
                            }
557 3
                            $mainStack->push($altStack->pop());
558 3
                            break;
559
560 955
                        case Opcodes::OP_IFDUP:
561
                            // If top value not zero, duplicate it.
562 6
                            if ($mainStack->isEmpty()) {
563 2
                                throw new \RuntimeException('Invalid stack operation OP_IFDUP');
564
                            }
565 4
                            $vch = $mainStack[-1];
566 4
                            if ($this->castToBool($vch)) {
567 3
                                $mainStack->push($vch);
568
                            }
569 4
                            break;
570
571 952
                        case Opcodes::OP_DEPTH:
572 77
                            $num = count($mainStack);
573 77
                            $depth = Number::int($num)->getBuffer();
574 77
                            $mainStack->push($depth);
575 77
                            break;
576
577 943
                        case Opcodes::OP_DROP:
578 48
                            if ($mainStack->isEmpty()) {
579 2
                                throw new \RuntimeException('Invalid stack operation OP_DROP');
580
                            }
581 46
                            $mainStack->pop();
582 46
                            break;
583
584 940
                        case Opcodes::OP_DUP:
585 62
                            if ($mainStack->isEmpty()) {
586 26
                                throw new \RuntimeException('Invalid stack operation OP_DUP');
587
                            }
588 60
                            $vch = $mainStack[-1];
589 60
                            $mainStack->push($vch);
590 60
                            break;
591
592 931
                        case Opcodes::OP_NIP:
593 6
                            if (count($mainStack) < 2) {
594 3
                                throw new \RuntimeException('Invalid stack operation OP_NIP');
595
                            }
596 3
                            unset($mainStack[-2]);
597 3
                            break;
598
599 925
                        case Opcodes::OP_OVER:
600 6
                            if (count($mainStack) < 2) {
601 3
                                throw new \RuntimeException('Invalid stack operation OP_OVER');
602
                            }
603 3
                            $vch = $mainStack[-2];
604 3
                            $mainStack->push($vch);
605 3
                            break;
606
607 921
                        case Opcodes::OP_ROT:
608 12
                            if (count($mainStack) < 3) {
609 4
                                throw new \RuntimeException('Invalid stack operation OP_ROT');
610
                            }
611 8
                            $mainStack->swap(-3, -2);
612 8
                            $mainStack->swap(-2, -1);
613 8
                            break;
614
615 915
                        case Opcodes::OP_SWAP:
616 10
                            if (count($mainStack) < 2) {
617 3
                                throw new \RuntimeException('Invalid stack operation OP_SWAP');
618
                            }
619 7
                            $mainStack->swap(-2, -1);
620 7
                            break;
621
622 911
                        case Opcodes::OP_TUCK:
623 6
                            if (count($mainStack) < 2) {
624 3
                                throw new \RuntimeException('Invalid stack operation OP_TUCK');
625
                            }
626 3
                            $vch = $mainStack[-1];
627 3
                            $mainStack->add(- 2, $vch);
628 3
                            break;
629
630 907
                        case Opcodes::OP_PICK:
631 898
                        case Opcodes::OP_ROLL:
632 29
                            if (count($mainStack) < 2) {
633 4
                                throw new \RuntimeException('Invalid stack operation OP_PICK');
634
                            }
635
636 25
                            $n = Number::buffer($mainStack[-1], $minimal, 4)->getGmp();
637 23
                            $mainStack->pop();
638 23
                            if ($this->math->cmp($n, $zero) < 0 || $this->math->cmp($n, gmp_init(count($mainStack))) >= 0) {
639 5
                                throw new \RuntimeException('Invalid stack operation OP_PICK');
640
                            }
641
642 18
                            $pos = (int) gmp_strval($this->math->sub($this->math->sub($zero, $n), gmp_init(1)), 10);
643 18
                            $vch = $mainStack[$pos];
644 18
                            if ($opCode === Opcodes::OP_ROLL) {
645 9
                                unset($mainStack[$pos]);
646
                            }
647 18
                            $mainStack->push($vch);
648 18
                            break;
649
650 890
                        case Opcodes::OP_2DROP:
651 9
                            if (count($mainStack) < 2) {
652 1
                                throw new \RuntimeException('Invalid stack operation OP_2DROP');
653
                            }
654 8
                            $mainStack->pop();
655 8
                            $mainStack->pop();
656 8
                            break;
657
658 888
                        case Opcodes::OP_2DUP:
659 6
                            if (count($mainStack) < 2) {
660 3
                                throw new \RuntimeException('Invalid stack operation OP_2DUP');
661
                            }
662 3
                            $string1 = $mainStack[-2];
663 3
                            $string2 = $mainStack[-1];
664 3
                            $mainStack->push($string1);
665 3
                            $mainStack->push($string2);
666 3
                            break;
667
668 884
                        case Opcodes::OP_3DUP:
669 11
                            if (count($mainStack) < 3) {
670 4
                                throw new \RuntimeException('Invalid stack operation OP_3DUP');
671
                            }
672 7
                            $string1 = $mainStack[-3];
673 7
                            $string2 = $mainStack[-2];
674 7
                            $string3 = $mainStack[-1];
675 7
                            $mainStack->push($string1);
676 7
                            $mainStack->push($string2);
677 7
                            $mainStack->push($string3);
678 7
                            break;
679
680 874
                        case Opcodes::OP_2OVER:
681 5
                            if (count($mainStack) < 4) {
682 3
                                throw new \RuntimeException('Invalid stack operation OP_2OVER');
683
                            }
684 2
                            $string1 = $mainStack[-4];
685 2
                            $string2 = $mainStack[-3];
686 2
                            $mainStack->push($string1);
687 2
                            $mainStack->push($string2);
688 2
                            break;
689
690 870
                        case Opcodes::OP_2ROT:
691 10
                            if (count($mainStack) < 6) {
692 1
                                throw new \RuntimeException('Invalid stack operation OP_2ROT');
693
                            }
694 9
                            $string1 = $mainStack[-6];
695 9
                            $string2 = $mainStack[-5];
696 9
                            unset($mainStack[-6], $mainStack[-5]);
697 9
                            $mainStack->push($string1);
698 9
                            $mainStack->push($string2);
699 9
                            break;
700
701 868
                        case Opcodes::OP_2SWAP:
702 5
                            if (count($mainStack) < 4) {
703 3
                                throw new \RuntimeException('Invalid stack operation OP_2SWAP');
704
                            }
705 2
                            $mainStack->swap(-3, -1);
706 2
                            $mainStack->swap(-4, -2);
707 2
                            break;
708
709 864
                        case Opcodes::OP_SIZE:
710 31
                            if ($mainStack->isEmpty()) {
711 2
                                throw new \RuntimeException('Invalid stack operation OP_SIZE');
712
                            }
713 29
                            $size = Number::int($mainStack[-1]->getSize());
714 29
                            $mainStack->push($size->getBuffer());
715 29
                            break;
716
717 861
                        case Opcodes::OP_EQUAL:
718 750
                        case Opcodes::OP_EQUALVERIFY:
719 370
                            if (count($mainStack) < 2) {
720 4
                                throw new \RuntimeException('Invalid stack operation OP_EQUAL');
721
                            }
722
723 366
                            $equal = $mainStack[-2]->equals($mainStack[-1]);
724 366
                            $mainStack->pop();
725 366
                            $mainStack->pop();
726 366
                            $mainStack->push($equal ? $this->vchTrue : $this->vchFalse);
727 366
                            if ($opCode === Opcodes::OP_EQUALVERIFY) {
728 79
                                if ($equal) {
729 68
                                    $mainStack->pop();
730
                                } else {
731 11
                                    throw new \RuntimeException('Error EQUALVERIFY');
732
                                }
733
                            }
734
735 356
                            break;
736
737
                        // Arithmetic operations
738 719
                        case $opCode >= Opcodes::OP_1ADD && $opCode <= Opcodes::OP_0NOTEQUAL:
739 120
                            if ($mainStack->isEmpty()) {
740 6
                                throw new \Exception('Invalid stack operation 1ADD-OP_0NOTEQUAL');
741
                            }
742
743 114
                            $num = Number::buffer($mainStack[-1], $minimal)->getGmp();
744
745 91
                            if ($opCode === Opcodes::OP_1ADD) {
746 7
                                $num = $this->math->add($num, gmp_init(1));
747 84
                            } elseif ($opCode === Opcodes::OP_1SUB) {
748 3
                                $num = $this->math->sub($num, gmp_init(1));
749 81
                            } elseif ($opCode === Opcodes::OP_2MUL) {
750
                                $num = $this->math->mul(gmp_init(2), $num);
751 81
                            } elseif ($opCode === Opcodes::OP_NEGATE) {
752 4
                                $num = $this->math->sub($zero, $num);
753 78
                            } elseif ($opCode === Opcodes::OP_ABS) {
754 5
                                if ($this->math->cmp($num, $zero) < 0) {
755 5
                                    $num = $this->math->sub($zero, $num);
756
                                }
757 73
                            } elseif ($opCode === Opcodes::OP_NOT) {
758 67
                                $num = gmp_init($this->math->cmp($num, $zero) === 0 ? 1 : 0);
759
                            } else {
760
                                // is OP_0NOTEQUAL
761 6
                                $num = gmp_init($this->math->cmp($num, $zero) !== 0 ? 1 : 0);
762
                            }
763
764 91
                            $mainStack->pop();
765
766 91
                            $buffer = Number::int(gmp_strval($num, 10))->getBuffer();
767
768 91
                            $mainStack->push($buffer);
769 91
                            break;
770
771 660
                        case $opCode >= Opcodes::OP_ADD && $opCode <= Opcodes::OP_MAX:
772 164
                            if (count($mainStack) < 2) {
773 13
                                throw new \Exception('Invalid stack operation (OP_ADD - OP_MAX)');
774
                            }
775
776 151
                            $num1 = Number::buffer($mainStack[-2], $minimal)->getGmp();
777 134
                            $num2 = Number::buffer($mainStack[-1], $minimal)->getGmp();
778
779 121
                            if ($opCode === Opcodes::OP_ADD) {
780 30
                                $num = $this->math->add($num1, $num2);
781 97
                            } else if ($opCode === Opcodes::OP_SUB) {
782 6
                                $num = $this->math->sub($num1, $num2);
783 91
                            } else if ($opCode === Opcodes::OP_BOOLAND) {
784 8
                                $num = $this->math->cmp($num1, $zero) !== 0 && $this->math->cmp($num2, $zero) !== 0;
785 83
                            } else if ($opCode === Opcodes::OP_BOOLOR) {
786 8
                                $num = $this->math->cmp($num1, $zero) !== 0 || $this->math->cmp($num2, $zero) !== 0;
787 75
                            } elseif ($opCode === Opcodes::OP_NUMEQUAL) {
788 28
                                $num = $this->math->cmp($num1, $num2) === 0;
789 55
                            } elseif ($opCode === Opcodes::OP_NUMEQUALVERIFY) {
790 4
                                $num = $this->math->cmp($num1, $num2) === 0;
791 51
                            } elseif ($opCode === Opcodes::OP_NUMNOTEQUAL) {
792 5
                                $num = $this->math->cmp($num1, $num2) !== 0;
793 46
                            } elseif ($opCode === Opcodes::OP_LESSTHAN) {
794 8
                                $num = $this->math->cmp($num1, $num2) < 0;
795 38
                            } elseif ($opCode === Opcodes::OP_GREATERTHAN) {
796 8
                                $num = $this->math->cmp($num1, $num2) > 0;
797 30
                            } elseif ($opCode === Opcodes::OP_LESSTHANOREQUAL) {
798 8
                                $num = $this->math->cmp($num1, $num2) <= 0;
799 22
                            } elseif ($opCode === Opcodes::OP_GREATERTHANOREQUAL) {
800 8
                                $num = $this->math->cmp($num1, $num2) >= 0;
801 14
                            } elseif ($opCode === Opcodes::OP_MIN) {
802 7
                                $num = ($this->math->cmp($num1, $num2) <= 0) ? $num1 : $num2;
803
                            } else {
804 7
                                $num = ($this->math->cmp($num1, $num2) >= 0) ? $num1 : $num2;
805
                            }
806
807 121
                            $mainStack->pop();
808 121
                            $mainStack->pop();
809 121
                            $buffer = Number::int(gmp_strval($num, 10))->getBuffer();
810 121
                            $mainStack->push($buffer);
811
812 121
                            if ($opCode === Opcodes::OP_NUMEQUALVERIFY) {
813 4
                                if ($this->castToBool($mainStack[-1])) {
814 4
                                    $mainStack->pop();
815
                                } else {
816
                                    throw new \RuntimeException('NUM EQUAL VERIFY error');
817
                                }
818
                            }
819 121
                            break;
820
821 496
                        case Opcodes::OP_WITHIN:
822 15
                            if (count($mainStack) < 3) {
823 1
                                throw new \RuntimeException('Invalid stack operation');
824
                            }
825
826 14
                            $num1 = Number::buffer($mainStack[-3], $minimal)->getGmp();
827 13
                            $num2 = Number::buffer($mainStack[-2], $minimal)->getGmp();
828 12
                            $num3 = Number::buffer($mainStack[-1], $minimal)->getGmp();
829
830 11
                            $value = $this->math->cmp($num2, $num1) <= 0 && $this->math->cmp($num1, $num3) < 0;
831 11
                            $mainStack->pop();
832 11
                            $mainStack->pop();
833 11
                            $mainStack->pop();
834 11
                            $mainStack->push($value ? $this->vchTrue : $this->vchFalse);
835 11
                            break;
836
837
                        // Hash operation
838 481
                        case Opcodes::OP_RIPEMD160:
839 475
                        case Opcodes::OP_SHA1:
840 467
                        case Opcodes::OP_SHA256:
841 461
                        case Opcodes::OP_HASH160:
842 390
                        case Opcodes::OP_HASH256:
843 161
                            if ($mainStack->isEmpty()) {
844 12
                                throw new \RuntimeException('Invalid stack operation');
845
                            }
846
847 149
                            $buffer = $mainStack[-1];
848 149
                            if ($opCode === Opcodes::OP_RIPEMD160) {
849 5
                                $hash = Hash::ripemd160($buffer);
850 145
                            } elseif ($opCode === Opcodes::OP_SHA1) {
851 6
                                $hash = Hash::sha1($buffer);
852 139
                            } elseif ($opCode === Opcodes::OP_SHA256) {
853 6
                                $hash = Hash::sha256($buffer);
854 135
                            } elseif ($opCode === Opcodes::OP_HASH160) {
855 130
                                $hash = Hash::sha256ripe160($buffer);
856
                            } else {
857 5
                                $hash = Hash::sha256d($buffer);
858
                            }
859
860 149
                            $mainStack->pop();
861 149
                            $mainStack->push($hash);
862 149
                            break;
863
864 383
                        case Opcodes::OP_CODESEPARATOR:
865 1
                            $hashStartPos = $parser->getPosition();
866 1
                            break;
867
868 382
                        case Opcodes::OP_CHECKSIG:
869 233
                        case Opcodes::OP_CHECKSIGVERIFY:
870 149
                            if (count($mainStack) < 2) {
871 12
                                throw new \RuntimeException('Invalid stack operation');
872
                            }
873
874 147
                            $vchPubKey = $mainStack[-1];
875 147
                            $vchSig = $mainStack[-2];
876
877 147
                            $scriptCode = new Script($script->getBuffer()->slice($hashStartPos));
878
879 147
                            $success = $checker->checkSig($scriptCode, $vchSig, $vchPubKey, $sigVersion, $flags);
880
881 105
                            $mainStack->pop();
882 105
                            $mainStack->pop();
883 105
                            $mainStack->push($success ? $this->vchTrue : $this->vchFalse);
884
885 105
                            if (!$success && ($flags & self::VERIFY_NULLFAIL) && $vchSig->getSize() > 0) {
886 2
                                throw new ScriptRuntimeException(self::VERIFY_NULLFAIL, 'Signature must be zero for failed OP_CHECK(MULTIS)SIG operation');
887
                            }
888
889 103
                            if ($opCode === Opcodes::OP_CHECKSIGVERIFY) {
890
                                if ($success) {
891
                                    $mainStack->pop();
892
                                } else {
893
                                    throw new \RuntimeException('Checksig verify');
894
                                }
895
                            }
896 103
                            break;
897
898 233
                        case Opcodes::OP_CHECKMULTISIG:
899 129
                        case Opcodes::OP_CHECKMULTISIGVERIFY:
900 136
                            $i = 1;
901 136
                            if (count($mainStack) < $i) {
902 1
                                throw new \RuntimeException('Invalid stack operation');
903
                            }
904
905 135
                            $keyCount = Number::buffer($mainStack[-$i], $minimal)->getInt();
906 133
                            if ($keyCount < 0 || $keyCount > 20) {
907 2
                                throw new \RuntimeException('OP_CHECKMULTISIG: Public key count exceeds 20');
908
                            }
909
910 131
                            $opCount += $keyCount;
911 131
                            $this->checkOpcodeCount($opCount);
912
913
                            // Extract positions of the keys, and signatures, from the stack.
914 131
                            $ikey = ++$i;
915 131
                            $ikey2 = $keyCount + 2;
916 131
                            $i += $keyCount;
917 131
                            if (count($mainStack) < $i) {
918 1
                                throw new \RuntimeException('Invalid stack operation');
919
                            }
920
921 130
                            $sigCount = Number::buffer($mainStack[-$i], $minimal)->getInt();
922 127
                            if ($sigCount < 0 || $sigCount > $keyCount) {
923 2
                                throw new \RuntimeException('Invalid Signature count');
924
                            }
925
926 125
                            $isig = ++$i;
927 125
                            $i += $sigCount;
928
929
                            // Extract the script since the last OP_CODESEPARATOR
930 125
                            $scriptCode = new Script($script->getBuffer()->slice($hashStartPos));
931
932 125
                            $fSuccess = true;
933 125
                            while ($fSuccess && $sigCount > 0) {
934
                                // Fetch the signature and public key
935 65
                                $sig = $mainStack[-$isig];
936 64
                                $pubkey = $mainStack[-$ikey];
937
938 64
                                if ($checker->checkSig($scriptCode, $sig, $pubkey, $sigVersion, $flags)) {
939 26
                                    $isig++;
940 26
                                    $sigCount--;
941
                                }
942
943 56
                                $ikey++;
944 56
                                $keyCount--;
945
946
                                // If there are more signatures left than keys left,
947
                                // then too many signatures have failed. Exit early,
948
                                // without checking any further signatures.
949 56
                                if ($sigCount > $keyCount) {
950 42
                                    $fSuccess = false;
951
                                }
952
                            }
953
954 112
                            while ($i-- > 1) {
955
                                // If the operation failed, we require that all signatures must be empty vector
956 112
                                if (!$fSuccess && ($flags & self::VERIFY_NULLFAIL) && !$ikey2 && $mainStack[-1]->getSize() > 0) {
957 4
                                    throw new ScriptRuntimeException(self::VERIFY_NULLFAIL, 'Bad signature must be empty vector');
958
                                }
959
960 112
                                if ($ikey2 > 0) {
961 112
                                    $ikey2--;
962
                                }
963
964 112
                                $mainStack->pop();
965
                            }
966
967
                            // A bug causes CHECKMULTISIG to consume one extra argument
968
                            // whose contents were not checked in any way.
969
                            //
970
                            // Unfortunately this is a potential source of mutability,
971
                            // so optionally verify it is exactly equal to zero prior
972
                            // to removing it from the stack.
973 108
                            if ($mainStack->isEmpty()) {
974 9
                                throw new \RuntimeException('Invalid stack operation');
975
                            }
976
977 108
                            if ($flags & self::VERIFY_NULL_DUMMY && $mainStack[-1]->getSize() !== 0) {
978 4
                                throw new ScriptRuntimeException(self::VERIFY_NULL_DUMMY, 'Extra P2SH stack value should be OP_0');
979
                            }
980
981 104
                            $mainStack->pop();
982 104
                            $mainStack->push($fSuccess ? $this->vchTrue : $this->vchFalse);
983
984 104
                            if ($opCode === Opcodes::OP_CHECKMULTISIGVERIFY) {
985 30
                                if ($fSuccess) {
986 30
                                    $mainStack->pop();
987
                                } else {
988
                                    throw new \RuntimeException('OP_CHECKMULTISIG verify');
989
                                }
990
                            }
991 104
                            break;
992
993
                        default:
994 97
                            throw new \RuntimeException('Opcode not found');
995
                    }
996
997 1099
                    if (count($mainStack) + count($altStack) > 1000) {
998 1240
                        throw new \RuntimeException('Invalid stack size, exceeds 1000');
999
                    }
1000
                }
1001
            }
1002
1003 1240
            if (count($vfStack) !== 0) {
1004 6
                throw new \RuntimeException('Unbalanced conditional at script end');
1005
            }
1006
1007 1235
            return true;
1008 497
        } catch (ScriptRuntimeException $e) {
1009
            // echo "\n Runtime: " . $e->getMessage() . "\n" . $e->getTraceAsString() . PHP_EOL;
1010
            // Failure due to script tags, can access flag: $e->getFailureFlag()
1011 112
            return false;
1012 385
        } catch (\Exception $e) {
1013
            // echo "\n General: " . $e->getMessage()  . PHP_EOL . $e->getTraceAsString() . PHP_EOL;
1014 385
            return false;
1015
        }
1016
    }
1017
}
1018