Completed
Push — master ( af1b10...bf42d9 )
by thomas
24:09
created

Interpreter::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 1

Importance

Changes 5
Bugs 0 Features 0
Metric Value
c 5
b 0
f 0
dl 0
loc 9
ccs 8
cts 8
cp 1
rs 9.6666
cc 1
eloc 7
nc 1
nop 1
crap 1
1
<?php
2
3
namespace BitWasp\Bitcoin\Script\Interpreter;
4
5
use BitWasp\Bitcoin\Crypto\EcAdapter\Adapter\EcAdapterInterface;
6
use BitWasp\Bitcoin\Crypto\Hash;
7
use BitWasp\Bitcoin\Exceptions\SignatureNotCanonical;
8
use BitWasp\Bitcoin\Exceptions\ScriptRuntimeException;
9
use BitWasp\Bitcoin\Script\Classifier\OutputClassifier;
10
use BitWasp\Bitcoin\Script\Opcodes;
11
use BitWasp\Bitcoin\Script\Script;
12
use BitWasp\Bitcoin\Script\ScriptFactory;
13
use BitWasp\Bitcoin\Script\ScriptInterface;
14
use BitWasp\Bitcoin\Script\ScriptWitness;
15
use BitWasp\Bitcoin\Script\ScriptWitnessInterface;
16
use BitWasp\Bitcoin\Script\WitnessProgram;
17
use BitWasp\Bitcoin\Signature\TransactionSignature;
18
use BitWasp\Bitcoin\Transaction\TransactionInputInterface;
19
use BitWasp\Buffertools\Buffer;
20
use BitWasp\Buffertools\BufferInterface;
21
22
class Interpreter implements InterpreterInterface
23
{
24
25
    /**
26
     * @var int
27
     */
28
    private $opCount;
29
30
    /**
31
     * @var EcAdapterInterface
32
     */
33
    private $ecAdapter;
34
35
    /**
36
     * @var \BitWasp\Bitcoin\Math\Math
37
     */
38
    private $math;
39
40
    /**
41
     * @var BufferInterface
42
     */
43
    private $vchFalse;
44
45
    /**
46
     * @var BufferInterface
47
     */
48
    private $vchTrue;
49
50
    /**
51
     * @var BufferInterface
52
     */
53
    private $int0;
54
55
    /**
56
     * @var BufferInterface
57
     */
58
    private $int1;
59
60
    /**
61
     * @var array
62
     */
63
    private $disabledOps = [
64
        Opcodes::OP_CAT,    Opcodes::OP_SUBSTR, Opcodes::OP_LEFT,  Opcodes::OP_RIGHT,
65
        Opcodes::OP_INVERT, Opcodes::OP_AND,    Opcodes::OP_OR,    Opcodes::OP_XOR,
66
        Opcodes::OP_2MUL,   Opcodes::OP_2DIV,   Opcodes::OP_MUL,   Opcodes::OP_DIV,
67
        Opcodes::OP_MOD,    Opcodes::OP_LSHIFT, Opcodes::OP_RSHIFT
68
    ];
69
70
    /**
71
     * @param EcAdapterInterface $ecAdapter
72
     */
73 1458
    public function __construct(EcAdapterInterface $ecAdapter)
74
    {
75 1458
        $this->ecAdapter = $ecAdapter;
76 1458
        $this->math = $ecAdapter->getMath();
77 1458
        $this->vchFalse = new Buffer("", 0, $this->math);
78 1458
        $this->vchTrue = new Buffer("\x01", 1, $this->math);
79 1458
        $this->int0 = Number::buffer($this->vchFalse, false, 4, $this->math)->getBuffer();
80 1458
        $this->int1 = Number::buffer($this->vchTrue, false, 1, $this->math)->getBuffer();
81 1458
    }
82
83
    /**
84
     * Cast the value to a boolean
85
     *
86
     * @param BufferInterface $value
87
     * @return bool
88
     */
89 540
    public function castToBool(BufferInterface $value)
90
    {
91 540
        $val = $value->getBinary();
92 540
        for ($i = 0, $size = strlen($val); $i < $size; $i++) {
93 534
            $chr = ord($val[$i]);
94 534
            if ($chr != 0) {
95 516
                if ($i == ($size - 1) && $chr == 0x80) {
96
                    return false;
97
                }
98
99 516
                return true;
100
            }
101 48
        }
102
103 30
        return false;
104
    }
105
106
    /**
107
     * @param BufferInterface $signature
108
     * @return bool
109
     */
110
    public function isValidSignatureEncoding(BufferInterface $signature)
111
    {
112
        try {
113
            TransactionSignature::isDERSignature($signature);
114
            return true;
115
        } catch (SignatureNotCanonical $e) {
116
            /* In any case, we will return false outside this block */
117
        }
118
119
        return false;
120
    }
121
122
    /**
123
     * @param int $opCode
124
     * @param BufferInterface $pushData
125
     * @return bool
126
     * @throws \Exception
127
     */
128 18
    public function checkMinimalPush($opCode, BufferInterface $pushData)
129
    {
130 18
        $pushSize = $pushData->getSize();
131 18
        $binary = $pushData->getBinary();
132
133 18
        if ($pushSize === 0) {
134 6
            return $opCode === Opcodes::OP_0;
135 18
        } elseif ($pushSize === 1) {
136 6
            $first = ord($binary[0]);
137 6
            if ($first >= 1 && $first <= 16) {
138 6
                return $opCode === (Opcodes::OP_1 + ($first - 1));
139 6
            } elseif ($first === 0x81) {
140 6
                return $opCode === Opcodes::OP_1NEGATE;
141
            }
142 18
        } elseif ($pushSize <= 75) {
143 18
            return $opCode === $pushSize;
144 6
        } elseif ($pushSize <= 255) {
145 6
            return $opCode === Opcodes::OP_PUSHDATA1;
146 6
        } elseif ($pushSize <= 65535) {
147 6
            return $opCode === Opcodes::OP_PUSHDATA2;
148
        }
149
150 6
        return true;
151
    }
152
153
    /**
154
     * @return $this
155
     * @throws \Exception
156
     */
157 1410
    private function checkOpcodeCount()
158
    {
159 1410
        if ($this->math->cmp($this->opCount, 201) > 0) {
160 12
            throw new \RuntimeException('Error: Script op code count');
161
        }
162
163 1410
        return $this;
164
    }
165
166
    /**
167
     * @param WitnessProgram $witnessProgram
168
     * @param ScriptWitness $scriptWitness
169
     * @param int $flags
170
     * @param Checker $checker
171
     * @return bool
172
     */
173 30
    private function verifyWitnessProgram(WitnessProgram $witnessProgram, ScriptWitness $scriptWitness, $flags, Checker $checker)
174
    {
175 30
        $witnessCount = count($scriptWitness);
176
177 30
        if ($witnessProgram->getVersion() == 0) {
178 30
            $buffer = $witnessProgram->getProgram();
179 30
            if ($buffer->getSize() === 32) {
180
                // Version 0 segregated witness program: SHA256(Script) in program, Script + inputs in witness
181 18
                if ($witnessCount === 0) {
182
                    // Must contain script at least
183
                    return false;
184
                }
185
186 18
                $scriptPubKey = new Script($scriptWitness[$witnessCount - 1]);
187 18
                $stackValues = $scriptWitness->slice(0, -1);
188 18
                $hashScriptPubKey = Hash::sha256($scriptPubKey->getBuffer());
189
190 18
                if ($hashScriptPubKey == $buffer) {
191
                    return false;
192
                }
193 30
            } elseif ($buffer->getSize() === 20) {
194
                // Version 0 special case for pay-to-pubkeyhash
195 12
                if ($witnessCount !== 2) {
196
                    // 2 items in witness - <signature> <pubkey>
197
                    return false;
198
                }
199
200 12
                $scriptPubKey = ScriptFactory::create()->sequence([Opcodes::OP_DUP, Opcodes::OP_HASH160, $buffer, Opcodes::OP_EQUALVERIFY, Opcodes::OP_CHECKSIG])->getScript();
201 12
                $stackValues = $scriptWitness;
202 12
            } else {
203
                return false;
204
            }
205 30
        } elseif ($flags & self::VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM) {
206
            return false;
207
        } else {
208
            return false;
209
        }
210
211 30
        $mainStack = new Stack();
212 30
        foreach ($stackValues as $value) {
213 30
            $mainStack->push($value);
214 30
        }
215
216 30
        if (!$this->evaluate($scriptPubKey, $mainStack, 1, $flags, $checker)) {
217
            return false;
218
        }
219
220 30
        if ($mainStack->count() !== 1) {
221
            return false;
222
        }
223
224 30
        if (!$this->castToBool($mainStack->bottom())) {
225
            return false;
226
        }
227
228 30
        return true;
229
    }
230
231
    /**
232
     * @param ScriptInterface $scriptSig
233
     * @param ScriptInterface $scriptPubKey
234
     * @param int $flags
235
     * @param Checker $checker
236
     * @param ScriptWitnessInterface|null $witness
237
     * @return bool
238
     */
239 780
    public function verify(ScriptInterface $scriptSig, ScriptInterface $scriptPubKey, $flags, Checker $checker, ScriptWitnessInterface $witness = null)
240
    {
241 780
        static $emptyWitness = null;
242 780
        if ($emptyWitness === null) {
243 6
            $emptyWitness = new ScriptWitness([]);
244 6
        }
245
246 780
        $witness = $witness ?: $emptyWitness;
247
248 780
        if (($flags & self::VERIFY_SIGPUSHONLY) != 0 && !$scriptSig->isPushOnly()) {
249
            return false;
250
        }
251
252 780
        $stack = new Stack();
253 780
        if (!$this->evaluate($scriptSig, $stack, 0, $flags, $checker)) {
254 6
            return false;
255
        }
256
257 774
        $backup = [];
258 774
        if ($flags & self::VERIFY_P2SH) {
259 90
            foreach ($stack as $s) {
260 66
                $backup[] = $s;
261 90
            }
262 90
        }
263
264 774
        if (!$this->evaluate($scriptPubKey, $stack, 0, $flags, $checker)) {
265 270
            return false;
266
        }
267
268 504
        if ($stack->isEmpty()) {
269 6
            return false;
270
        }
271
272 498
        if (false === $this->castToBool($stack[-1])) {
273 6
            return false;
274
        }
275
276 492
        $program = null;
277
278 492
        if ($flags & self::VERIFY_WITNESS) {
279 72
            if ($scriptPubKey->isWitness($program)) {
0 ignored issues
show
Documentation introduced by
$program is of type null, but the function expects a object<BitWasp\Bitcoin\Script\WitnessProgram>.

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...
280
                /** @var WitnessProgram $program */
281 18
                if ($scriptSig->getBuffer()->getSize() !== 0) {
282
                    return false;
283
                }
284
285 18
                if (!$this->verifyWitnessProgram($program, $witness, $flags, $checker)) {
0 ignored issues
show
Documentation introduced by
$witness is of type null|object<BitWasp\Bitc...ScriptWitnessInterface>, but the function expects a object<BitWasp\Bitcoin\Script\ScriptWitness>.

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...
286
                    return false;
287
                }
288
289 18
                $stack->resize(1);
290 18
            }
291 72
        }
292
293 492
        if ($flags & self::VERIFY_P2SH && (new OutputClassifier($scriptPubKey))->isPayToScriptHash()) {
294 36
            if (!$scriptSig->isPushOnly()) {
295 6
                return false;
296
            }
297
298 30
            $stack = new Stack();
299 30
            foreach ($backup as $i) {
300 30
                $stack->push($i);
301 30
            }
302
303
            // Restore mainStack to how it was after evaluating scriptSig
304 30
            if ($stack->isEmpty()) {
305
                return false;
306
            }
307
308
            // Load redeemscript as the scriptPubKey
309 30
            $scriptPubKey = new Script($stack->bottom());
310 30
            $stack->pop();
311
312 30
            if (!$this->evaluate($scriptPubKey, $stack, 0, $flags, $checker)) {
313 6
                return false;
314
            }
315
316 24
            if ($stack->isEmpty()) {
317
                return false;
318
            }
319
320 24
            if (!$this->castToBool($stack->bottom())) {
321
                return false;
322
            }
323
324 24
            if ($flags & self::VERIFY_WITNESS) {
325 24
                if ($scriptPubKey->isWitness($program)) {
326
                    /** @var WitnessProgram $program */
327 12
                    if ($scriptSig != (ScriptFactory::create()->push($scriptPubKey->getBuffer())->getScript())) {
328
                        return false; // SCRIPT_ERR_WITNESS_MALLEATED_P2SH
329
                    }
330
331 12
                    if (!$this->verifyWitnessProgram($program, $witness, $flags, $checker)) {
0 ignored issues
show
Documentation introduced by
$witness is of type null|object<BitWasp\Bitc...ScriptWitnessInterface>, but the function expects a object<BitWasp\Bitcoin\Script\ScriptWitness>.

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...
332
                        return false;
333
                    }
334
335 12
                    $stack->resize(1);
336 12
                }
337 24
            }
338 24
        }
339
340 480
        if ($flags & self::VERIFY_CLEAN_STACK != 0) {
341 72
            if (!($flags & self::VERIFY_P2SH != 0 && $flags & self::VERIFY_WITNESS != 0)) {
342
                return false; // implied flags required
343
            }
344
345 72
            if (count($stack) != 1) {
346
                return false; // Cleanstack
347
            }
348 72
        }
349
350 480
        if ($flags & self::VERIFY_WITNESS) {
351 72
            if (!$flags & self::VERIFY_P2SH) {
352
                return false; //
353
            }
354
355 72
            if ($program === null && !$witness->isNull()) {
356
                return false; // SCRIPT_ERR_WITNESS_UNEXPECTED
357
            }
358 72
        }
359
360 480
        return true;
361
    }
362
363
    /**
364
     * @param Stack $vfStack
365
     * @return bool
366
     */
367 1446
    private function checkExec(Stack $vfStack)
368
    {
369 1446
        $c = 0;
370 1446
        $len = $vfStack->end();
371 1446
        for ($i = 0; $i < $len; $i++) {
372
            if ($vfStack[0 - $len - $i] === true) {
373
                $c++;
374
            }
375
        }
376 1446
        return !(bool)$c;
377
    }
378
379
    /**
380
     * @param ScriptInterface $script
381
     * @param Stack $mainStack
382
     * @param int $sigVersion
383
     * @param int $flags
384
     * @param Checker $checker
385
     * @return bool
386
     */
387 1452
    public function evaluate(ScriptInterface $script, Stack $mainStack, $sigVersion, $flags, Checker $checker)
388
    {
389 1452
        $math = $this->math;
390 1452
        $hashStartPos = 0;
391 1452
        $this->opCount = 0;
392 1452
        $altStack = new Stack();
393 1452
        $vfStack = new Stack();
394 1452
        $minimal = (bool) ($flags & self::VERIFY_MINIMALDATA);
395 1452
        $parser = $script->getScriptParser();
396
397 1452
        if ($script->getBuffer()->getSize() > 10000) {
398
            return false;
399
        }
400
401
        try {
402 1452
            foreach ($parser as $operation) {
403 1446
                $opCode = $operation->getOp();
404 1446
                $pushData = $operation->getData();
405 1446
                $fExec = $this->checkExec($vfStack);
406
407
                // If pushdata was written to
408 1446
                if ($operation->isPush() && $operation->getDataSize() > InterpreterInterface::MAX_SCRIPT_ELEMENT_SIZE) {
409 6
                    throw new \RuntimeException('Error - push size');
410
                }
411
412
                // OP_RESERVED should not count towards opCount
413 1440
                if ($opCode > Opcodes::OP_16 && ++$this->opCount) {
414 1410
                    $this->checkOpcodeCount();
415 1410
                }
416
417 1440
                if (in_array($opCode, $this->disabledOps, true)) {
418 24
                    throw new \RuntimeException('Disabled Opcode');
419
                }
420
421 1440
                if ($fExec && $operation->isPush()) {
422
                    // In range of a pushdata opcode
423 912
                    if ($minimal && !$this->checkMinimalPush($opCode, $pushData)) {
424 12
                        throw new ScriptRuntimeException(self::VERIFY_MINIMALDATA, 'Minimal pushdata required');
425
                    }
426
427 900
                    $mainStack->push($pushData);
428
                    // echo " - [pushed '" . $pushData->getHex() . "']\n";
429 1428
                } elseif ($fExec || ($opCode !== Opcodes::OP_IF && $opCode !== Opcodes::OP_ENDIF)) {
430
                    // echo "OPCODE - " . $script->getOpcodes()->getOp($opCode) . "\n";
431
                    switch ($opCode) {
432 1386
                        case Opcodes::OP_1NEGATE:
433 1386
                        case Opcodes::OP_1:
434 1386
                        case Opcodes::OP_2:
435 1386
                        case Opcodes::OP_3:
436 1386
                        case Opcodes::OP_4:
437 1386
                        case Opcodes::OP_5:
438 1386
                        case Opcodes::OP_6:
439 1386
                        case Opcodes::OP_7:
440 1386
                        case Opcodes::OP_8:
441 1386
                        case Opcodes::OP_9:
442 1386
                        case Opcodes::OP_10:
443 1386
                        case Opcodes::OP_11:
444 1386
                        case Opcodes::OP_12:
445 1386
                        case Opcodes::OP_13:
446 1386
                        case Opcodes::OP_14:
447 1386
                        case Opcodes::OP_15:
448 1386
                        case Opcodes::OP_16:
449 414
                            $num = \BitWasp\Bitcoin\Script\decodeOpN($opCode);
450 414
                            $mainStack->push(Number::int($num)->getBuffer());
451 414
                            break;
452
453 1386
                        case Opcodes::OP_CHECKLOCKTIMEVERIFY:
454
                            if (!$flags & self::VERIFY_CHECKLOCKTIMEVERIFY) {
455
                                if ($flags & self::VERIFY_DISCOURAGE_UPGRADABLE_NOPS) {
456
                                    throw new ScriptRuntimeException(self::VERIFY_DISCOURAGE_UPGRADABLE_NOPS, 'Upgradable NOP found - this is discouraged');
457
                                }
458
                                break;
459
                            }
460
461
                            if ($mainStack->isEmpty()) {
462
                                throw new \RuntimeException('Invalid stack operation - CLTV');
463
                            }
464
465
                            $lockTime = Number::buffer($mainStack[-1], $minimal, 5, $math);
466
                            if (!$checker->checkLockTime($lockTime)) {
467
                                throw new ScriptRuntimeException(self::VERIFY_CHECKLOCKTIMEVERIFY, 'Unsatisfied locktime');
468
                            }
469
470
                            break;
471
472 1386
                        case Opcodes::OP_CHECKSEQUENCEVERIFY:
473
                            if (!$flags & self::VERIFY_CHECKSEQUENCEVERIFY) {
474
                                if ($flags & self::VERIFY_DISCOURAGE_UPGRADABLE_NOPS) {
475
                                    throw new ScriptRuntimeException(self::VERIFY_DISCOURAGE_UPGRADABLE_NOPS, 'Upgradable NOP found - this is discouraged');
476
                                }
477
                                break;
478
                            }
479
480
                            if ($mainStack->isEmpty()) {
481
                                throw new \RuntimeException('Invalid stack operation - CSV');
482
                            }
483
484
                            $sequence = Number::buffer($mainStack[-1], $minimal, 5, $math);
485
                            $nSequence = $sequence->getInt();
486
                            if ($math->cmp($nSequence, 0) < 0) {
487
                                throw new ScriptRuntimeException(self::VERIFY_CHECKSEQUENCEVERIFY, 'Negative locktime');
488
                            }
489
490
                            if ($math->cmp($math->bitwiseAnd($nSequence, TransactionInputInterface::SEQUENCE_LOCKTIME_DISABLE_FLAG), '0') !== 0) {
491
                                break;
492
                            }
493
494
                            if (!$checker->checkSequence($sequence)) {
495
                                throw new ScriptRuntimeException(self::VERIFY_CHECKSEQUENCEVERIFY, 'Unsatisfied locktime');
496
                            }
497
                            break;
498
499 1386
                        case Opcodes::OP_NOP1:
500 1386
                        case Opcodes::OP_NOP4:
501 1386
                        case Opcodes::OP_NOP5:
502 1386
                        case Opcodes::OP_NOP6:
503 1386
                        case Opcodes::OP_NOP7:
504 1386
                        case Opcodes::OP_NOP8:
505 1386
                        case Opcodes::OP_NOP9:
506 1386
                        case Opcodes::OP_NOP10:
507 12
                            if ($flags & self::VERIFY_DISCOURAGE_UPGRADABLE_NOPS) {
508 12
                                throw new ScriptRuntimeException(self::VERIFY_DISCOURAGE_UPGRADABLE_NOPS, 'Upgradable NOP found - this is discouraged');
509
                            }
510
                            break;
511
512 1374
                        case Opcodes::OP_NOP:
513 24
                            break;
514
515 1350
                        case Opcodes::OP_IF:
516 1350
                        case Opcodes::OP_NOTIF:
517
                            // <expression> if [statements] [else [statements]] endif
518 36
                            $value = false;
519 36
                            if ($fExec) {
520 36
                                if ($mainStack->isEmpty()) {
521 12
                                    throw new \RuntimeException('Unbalanced conditional');
522
                                }
523
                                // todo
524 24
                                $buffer = Number::buffer($mainStack->pop(), $minimal)->getBuffer();
525 24
                                $value = $this->castToBool($buffer);
526 24
                                if ($opCode === Opcodes::OP_NOTIF) {
527 12
                                    $value = !$value;
528 12
                                }
529 24
                            }
530 24
                            $vfStack->push($value ? $this->vchTrue : $this->vchFalse);
531 24
                            break;
532
533 1338
                        case Opcodes::OP_ELSE:
534 36
                            if ($vfStack->isEmpty()) {
535 12
                                throw new \RuntimeException('Unbalanced conditional');
536
                            }
537 24
                            $vfStack[-1] = !$vfStack->end() ? $this->vchTrue : $this->vchFalse;
538 24
                            break;
539
540 1326
                        case Opcodes::OP_ENDIF:
541 36
                            if ($vfStack->isEmpty()) {
542 12
                                throw new \RuntimeException('Unbalanced conditional');
543
                            }
544 24
                            break;
545
546 1314
                        case Opcodes::OP_VERIFY:
547 48
                            if ($mainStack->isEmpty()) {
548 12
                                throw new \RuntimeException('Invalid stack operation');
549
                            }
550 36
                            $value = $this->castToBool($mainStack[-1]);
551 36
                            if (!$value) {
552 12
                                throw new \RuntimeException('Error: verify');
553
                            }
554 24
                            $mainStack->pop();
555 24
                            break;
556
557 1266
                        case Opcodes::OP_RESERVED:
558
                            // todo
559 24
                            break;
560
561 1242
                        case Opcodes::OP_TOALTSTACK:
562 36
                            if ($mainStack->isEmpty()) {
563 12
                                throw new \RuntimeException('Invalid stack operation OP_TOALTSTACK');
564
                            }
565 24
                            $altStack->push($mainStack->pop());
566 24
                            break;
567
568 1230
                        case Opcodes::OP_FROMALTSTACK:
569 24
                            if ($altStack->isEmpty()) {
570 12
                                throw new \RuntimeException('Invalid alt-stack operation OP_FROMALTSTACK');
571
                            }
572 12
                            $mainStack->push($altStack->pop());
573 12
                            break;
574
575 1218
                        case Opcodes::OP_IFDUP:
576
                            // If top value not zero, duplicate it.
577 24
                            if ($mainStack->isEmpty()) {
578 12
                                throw new \RuntimeException('Invalid stack operation OP_IFDUP');
579
                            }
580 12
                            $vch = $mainStack[-1];
581 12
                            if ($this->castToBool($vch)) {
582 12
                                $mainStack->push($vch);
583 12
                            }
584 12
                            break;
585
586 1206
                        case Opcodes::OP_DEPTH:
587 150
                            $num = count($mainStack);
588 150
                            $depth = Number::int($num)->getBuffer();
589 150
                            $mainStack->push($depth);
590 150
                            break;
591
592 1206
                        case Opcodes::OP_DROP:
593 12
                            if ($mainStack->isEmpty()) {
594 12
                                throw new \RuntimeException('Invalid stack operation OP_DROP');
595
                            }
596
                            $mainStack->pop();
597
                            break;
598
599 1194
                        case Opcodes::OP_DUP:
600 54
                            if ($mainStack->isEmpty()) {
601 12
                                throw new \RuntimeException('Invalid stack operation OP_DUP');
602
                            }
603 42
                            $vch = $mainStack[-1];
604 42
                            $mainStack->push($vch);
605 42
                            break;
606
607 1182
                        case Opcodes::OP_NIP:
608 36
                            if (count($mainStack) < 2) {
609 12
                                throw new \RuntimeException('Invalid stack operation OP_NIP');
610
                            }
611 24
                            unset($mainStack[-2]);
612 24
                            break;
613
614 1170
                        case Opcodes::OP_OVER:
615 36
                            if (count($mainStack) < 2) {
616 12
                                throw new \RuntimeException('Invalid stack operation OP_OVER');
617
                            }
618 24
                            $vch = $mainStack[-2];
619 24
                            $mainStack->push($vch);
620 24
                            break;
621
622 1158
                        case Opcodes::OP_ROT:
623 24
                            if (count($mainStack) < 3) {
624 12
                                throw new \RuntimeException('Invalid stack operation OP_ROT');
625
                            }
626 12
                            $mainStack->swap(-3, -2);
627 12
                            $mainStack->swap(-2, -1);
628 12
                            break;
629
630 1146
                        case Opcodes::OP_SWAP:
631 24
                            if (count($mainStack) < 2) {
632 12
                                throw new \RuntimeException('Invalid stack operation OP_SWAP');
633
                            }
634 12
                            $mainStack->swap(-2, -1);
635 12
                            break;
636
637 1134
                        case Opcodes::OP_TUCK:
638 24
                            if (count($mainStack) < 2) {
639 12
                                throw new \RuntimeException('Invalid stack operation OP_TUCK');
640
                            }
641 12
                            $vch = $mainStack[-1];
642 12
                            $mainStack->add(count($mainStack) - 1 - 2, $vch);
643
                            break;
644
645 1110
                        case Opcodes::OP_PICK:
646 1110
                        case Opcodes::OP_ROLL:
647 48
                            if (count($mainStack) < 2) {
648 12
                                throw new \RuntimeException('Invalid stack operation OP_PICK');
649
                            }
650
651 36
                            $n = Number::buffer($mainStack[-1], $minimal, 4)->getInt();
652 36
                            $mainStack->pop();
653 36
                            if ($math->cmp($n, 0) < 0 || $math->cmp($n, count($mainStack)) >= 0) {
654 12
                                throw new \RuntimeException('Invalid stack operation OP_PICK');
655
                            }
656
657 24
                            $pos = (int) $math->sub($math->sub(0, $n), 1);
658 24
                            $vch = $mainStack[$pos];
659 24
                            if ($opCode === Opcodes::OP_ROLL) {
660 12
                                unset($mainStack[$pos]);
661 12
                            }
662 24
                            $mainStack->push($vch);
663 24
                            break;
664
665 1086
                        case Opcodes::OP_2DROP:
666 24
                            if (count($mainStack) < 2) {
667 12
                                throw new \RuntimeException('Invalid stack operation OP_2DROP');
668
                            }
669 12
                            $mainStack->pop();
670 12
                            $mainStack->pop();
671 12
                            break;
672
673 1074
                        case Opcodes::OP_2DUP:
674 36
                            if (count($mainStack) < 2) {
675 12
                                throw new \RuntimeException('Invalid stack operation OP_2DUP');
676
                            }
677 24
                            $string1 = $mainStack[-2];
678 24
                            $string2 = $mainStack[-1];
679 24
                            $mainStack->push($string1);
680 24
                            $mainStack->push($string2);
681 24
                            break;
682
683 1062
                        case Opcodes::OP_3DUP:
684 36
                            if (count($mainStack) < 3) {
685 12
                                throw new \RuntimeException('Invalid stack operation OP_3DUP');
686
                            }
687 24
                            $string1 = $mainStack[-3];
688 24
                            $string2 = $mainStack[-2];
689 24
                            $string3 = $mainStack[-1];
690 24
                            $mainStack->push($string1);
691 24
                            $mainStack->push($string2);
692 24
                            $mainStack->push($string3);
693 24
                            break;
694
695 1050
                        case Opcodes::OP_2OVER:
696 36
                            if (count($mainStack) < 4) {
697 12
                                throw new \RuntimeException('Invalid stack operation OP_2OVER');
698
                            }
699 24
                            $string1 = $mainStack[-4];
700 24
                            $string2 = $mainStack[-3];
701 24
                            $mainStack->push($string1);
702 24
                            $mainStack->push($string2);
703 24
                            break;
704
705 1038
                        case Opcodes::OP_2ROT:
706 24
                            if (count($mainStack) < 6) {
707 12
                                throw new \RuntimeException('Invalid stack operation OP_2ROT');
708
                            }
709 12
                            $string1 = $mainStack[-6];
710 12
                            $string2 = $mainStack[-5];
711 12
                            unset($mainStack[-6], $mainStack[-5]);
712 12
                            $mainStack->push($string1);
713 12
                            $mainStack->push($string2);
714 12
                            break;
715
716 1026
                        case Opcodes::OP_2SWAP:
717 24
                            if (count($mainStack) < 4) {
718 12
                                throw new \RuntimeException('Invalid stack operation OP_2SWAP');
719
                            }
720 12
                            $mainStack->swap(-3, -1);
721 12
                            $mainStack->swap(-4, -2);
722 12
                            break;
723
724 1014
                        case Opcodes::OP_SIZE:
725 24
                            if ($mainStack->isEmpty()) {
726 12
                                throw new \RuntimeException('Invalid stack operation OP_SIZE');
727
                            }
728
                            // todo: Int sizes?
729 12
                            $vch = $mainStack[-1];
730 12
                            $mainStack->push(Number::int($vch->getSize())->getBuffer());
731 12
                            break;
732
733 1002
                        case Opcodes::OP_EQUAL:
734 1002
                        case Opcodes::OP_EQUALVERIFY:
735 828
                            if (count($mainStack) < 2) {
736 12
                                throw new \RuntimeException('Invalid stack operation OP_EQUAL');
737
                            }
738 816
                            $vch1 = $mainStack[-2];
739 816
                            $vch2 = $mainStack[-1];
740
741 816
                            $equal = ($vch1->getBinary() === $vch2->getBinary());
742 816
                            $mainStack->pop();
743 816
                            $mainStack->pop();
744 816
                            $mainStack->push(($equal ? $this->vchTrue : $this->vchFalse));
745 816
                            if ($opCode === Opcodes::OP_EQUALVERIFY) {
746 246
                                if ($equal) {
747 222
                                    $mainStack->pop();
748 222
                                } else {
749 24
                                    throw new \RuntimeException('Error EQUALVERIFY');
750
                                }
751 222
                            }
752
753 792
                            break;
754
755
                        // Arithmetic operations
756 630
                        case $opCode >= Opcodes::OP_1ADD && $opCode <= Opcodes::OP_0NOTEQUAL:
757 96
                            if ($mainStack->isEmpty()) {
758 12
                                throw new \Exception('Invalid stack operation 1ADD-OP_0NOTEQUAL');
759
                            }
760
761 84
                            $num = Number::buffer($mainStack[-1], $minimal)->getInt();
762
763 84
                            if ($opCode === Opcodes::OP_1ADD) {
764 12
                                $num = $math->add($num, '1');
765 84
                            } elseif ($opCode === Opcodes::OP_1SUB) {
766 12
                                $num = $math->sub($num, '1');
767 72
                            } elseif ($opCode === Opcodes::OP_2MUL) {
768
                                $num = $math->mul(2, $num);
769 60
                            } elseif ($opCode === Opcodes::OP_NEGATE) {
770
                                $num = $math->sub(0, $num);
771 60
                            } elseif ($opCode === Opcodes::OP_ABS) {
772
                                if ($math->cmp($num, '0') < 0) {
773
                                    $num = $math->sub(0, $num);
774
                                }
775 60
                            } elseif ($opCode === Opcodes::OP_NOT) {
776 36
                                $num = (int) $math->cmp($num, '0') === 0;
777 36
                            } else {
778
                                // is OP_0NOTEQUAL
779 24
                                $num = (int) ($math->cmp($num, '0') !== 0);
780
                            }
781
782 84
                            $mainStack->pop();
783
784 84
                            $buffer = Number::int($num)->getBuffer();
785
786 84
                            $mainStack->push($buffer);
787 84
                            break;
788
789 534
                        case $opCode >= Opcodes::OP_ADD && $opCode <= Opcodes::OP_MAX:
790 300
                            if (count($mainStack) < 2) {
791 48
                                throw new \Exception('Invalid stack operation (OP_ADD - OP_MAX)');
792
                            }
793
794 252
                            $num1 = Number::buffer($mainStack[-2], $minimal)->getInt();
795 252
                            $num2 = Number::buffer($mainStack[-1], $minimal)->getInt();
796
797 252
                            if ($opCode === Opcodes::OP_ADD) {
798 12
                                $num = $math->add($num1, $num2);
799 252
                            } else if ($opCode === Opcodes::OP_SUB) {
800 12
                                $num = $math->sub($num1, $num2);
801 240
                            } else if ($opCode === Opcodes::OP_BOOLAND) {
802 24
                                $num = $math->cmp($num1, '0') !== 0 && $math->cmp($num2, '0') !== 0;
803 228
                            } else if ($opCode === Opcodes::OP_BOOLOR) {
804 36
                                $num = $math->cmp($num1, '0') !== 0 || $math->cmp($num2, '0') !== 0;
805 204
                            } elseif ($opCode === Opcodes::OP_NUMEQUAL) {
806 36
                                $num = $math->cmp($num1, $num2) === 0;
807 168
                            } elseif ($opCode === Opcodes::OP_NUMEQUALVERIFY) {
808
                                $num = $math->cmp($num1, $num2) === 0;
809 132
                            } elseif ($opCode === Opcodes::OP_NUMNOTEQUAL) {
810 12
                                $num = $math->cmp($num1, $num2) !== 0;
811 132
                            } elseif ($opCode === Opcodes::OP_LESSTHAN) {
812 24
                                $num = $math->cmp($num1, $num2) < 0;
813 120
                            } elseif ($opCode === Opcodes::OP_GREATERTHAN) {
814 24
                                $num = $math->cmp($num1, $num2) > 0;
815 96
                            } elseif ($opCode === Opcodes::OP_LESSTHANOREQUAL) {
816 24
                                $num = $math->cmp($num1, $num2) <= 0;
817 72
                            } elseif ($opCode === Opcodes::OP_GREATERTHANOREQUAL) {
818 24
                                $num = $math->cmp($num1, $num2) >= 0;
819 48
                            } elseif ($opCode === Opcodes::OP_MIN) {
820 12
                                $num = ($math->cmp($num1, $num2) <= 0) ? $num1 : $num2;
821 12
                            } else {
822 12
                                $num = ($math->cmp($num1, $num2) >= 0) ? $num1 : $num2;
823
                            }
824
825 252
                            $mainStack->pop();
826 252
                            $mainStack->pop();
827 252
                            $buffer = Number::int($num)->getBuffer();
828 252
                            $mainStack->push($buffer);
829
830 252
                            if ($opCode === Opcodes::OP_NUMEQUALVERIFY) {
831
                                if ($this->castToBool($mainStack[-1])) {
832
                                    $mainStack->pop();
833
                                } else {
834
                                    throw new \RuntimeException('NUM EQUAL VERIFY error');
835
                                }
836
                            }
837 252
                            break;
838
839 234
                        case Opcodes::OP_WITHIN:
840 24
                            if (count($mainStack) < 3) {
841 12
                                throw new \RuntimeException('Invalid stack operation');
842
                            }
843
844 12
                            $num1 = Number::buffer($mainStack[-3], $minimal)->getInt();
845 12
                            $num2 = Number::buffer($mainStack[-2], $minimal)->getInt();
846 12
                            $num3 = Number::buffer($mainStack[-1], $minimal)->getInt();
847
848 12
                            $value = $math->cmp($num2, $num1) <= 0 && $math->cmp($num1, $num3) < 0;
849 12
                            $mainStack->pop();
850 12
                            $mainStack->pop();
851 12
                            $mainStack->pop();
852 12
                            $mainStack->push($value ? $this->vchTrue : $this->vchFalse);
853 12
                            break;
854
855
                        // Hash operation
856 210
                        case Opcodes::OP_RIPEMD160:
857 210
                        case Opcodes::OP_SHA1:
858 210
                        case Opcodes::OP_SHA256:
859 210
                        case Opcodes::OP_HASH160:
860 210
                        case Opcodes::OP_HASH256:
861 138
                            if ($mainStack->isEmpty()) {
862 18
                                throw new \RuntimeException('Invalid stack operation');
863
                            }
864
865 120
                            $buffer = $mainStack[-1];
866 120
                            if ($opCode === Opcodes::OP_RIPEMD160) {
867 12
                                $hash = Hash::ripemd160($buffer);
868 120
                            } elseif ($opCode === Opcodes::OP_SHA1) {
869 12
                                $hash = Hash::sha1($buffer);
870 108
                            } elseif ($opCode === Opcodes::OP_SHA256) {
871 12
                                $hash = Hash::sha256($buffer);
872 96
                            } elseif ($opCode === Opcodes::OP_HASH160) {
873 72
                                $hash = Hash::sha256ripe160($buffer);
874 72
                            } else {
875 12
                                $hash = Hash::sha256d($buffer);
876
                            }
877
878 120
                            $mainStack->pop();
879 120
                            $mainStack->push($hash);
880 120
                            break;
881
882 126
                        case Opcodes::OP_CODESEPARATOR:
883
                            $hashStartPos = $parser->getPosition();
884
                            break;
885
886 126
                        case Opcodes::OP_CHECKSIG:
887 126
                        case Opcodes::OP_CHECKSIGVERIFY:
888 66
                            if (count($mainStack) < 2) {
889 12
                                throw new \RuntimeException('Invalid stack operation');
890
                            }
891
892 54
                            $vchPubKey = $mainStack[-1];
893 54
                            $vchSig = $mainStack[-2];
894
895 54
                            $scriptCode = new Script($script->getBuffer()->slice($hashStartPos));
896
897 54
                            $success = $checker->checkSig($scriptCode, $vchSig, $vchPubKey, $sigVersion, $flags);
898
899 42
                            $mainStack->pop();
900 42
                            $mainStack->pop();
901 42
                            $mainStack->push($success ? $this->vchTrue : $this->vchFalse);
902
903 42
                            if ($opCode === Opcodes::OP_CHECKSIGVERIFY) {
904
                                if ($success) {
905
                                    $mainStack->pop();
906
                                } else {
907
                                    throw new \RuntimeException('Checksig verify');
908
                                }
909
                            }
910 42
                            break;
911
912 60
                        case Opcodes::OP_CHECKMULTISIG:
913 60
                        case Opcodes::OP_CHECKMULTISIGVERIFY:
914 30
                            $i = 1;
915 30
                            if (count($mainStack) < $i) {
916
                                throw new \RuntimeException('Invalid stack operation');
917
                            }
918
919
920 30
                            $keyCount = Number::buffer($mainStack[-$i], $minimal)->getInt();
921 30
                            if ($math->cmp($keyCount, 0) < 0 || $math->cmp($keyCount, 20) > 0) {
922
                                throw new \RuntimeException('OP_CHECKMULTISIG: Public key count exceeds 20');
923
                            }
924
925 30
                            $this->opCount += $keyCount;
926 30
                            $this->checkOpcodeCount();
927
928
                            // Extract positions of the keys, and signatures, from the stack.
929 30
                            $ikey = ++$i;
930 30
                            $i += $keyCount; /** @var int $i */
931 30
                            if (count($mainStack) < $i) {
932
                                throw new \RuntimeException('Invalid stack operation');
933
                            }
934
935 30
                            $sigCount = Number::buffer($mainStack[-$i], $minimal)->getInt();
936 30
                            if ($math->cmp($sigCount, 0) < 0 || $math->cmp($sigCount, $keyCount) > 0) {
937
                                throw new \RuntimeException('Invalid Signature count');
938
                            }
939
940 30
                            $isig = ++$i;
941 30
                            $i += $sigCount;
942
943
                            // Extract the script since the last OP_CODESEPARATOR
944 30
                            $scriptCode = new Script($script->getBuffer()->slice($hashStartPos));
945
946 30
                            $fSuccess = true;
947 30
                            while ($fSuccess && $sigCount > 0) {
948
949
                                // Fetch the signature and public key
950 30
                                $sig = $mainStack[-$isig];
951 30
                                $pubkey = $mainStack[-$ikey];
952
953 30
                                if ($checker->checkSig($scriptCode, $sig, $pubkey, $sigVersion, $flags)) {
954 30
                                    $isig++;
955 30
                                    $sigCount--;
956 30
                                }
957
958 30
                                $ikey++;
959 30
                                $keyCount--;
960
961
                                // If there are more signatures left than keys left,
962
                                // then too many signatures have failed. Exit early,
963
                                // without checking any further signatures.
964 30
                                if ($sigCount > $keyCount) {
965
                                    $fSuccess = false;
966
                                }
967 30
                            }
968
969 30
                            while ($i-- > 1) {
970 30
                                $mainStack->pop();
971 30
                            }
972
973
                            // A bug causes CHECKMULTISIG to consume one extra argument
974
                            // whose contents were not checked in any way.
975
                            //
976
                            // Unfortunately this is a potential source of mutability,
977
                            // so optionally verify it is exactly equal to zero prior
978
                            // to removing it from the stack.
979 30
                            if ($mainStack->isEmpty()) {
980
                                throw new \RuntimeException('Invalid stack operation');
981
                            }
982
983 30
                            if ($flags & self::VERIFY_NULL_DUMMY && $mainStack[-1]->getSize() !== 0) {
984
                                throw new ScriptRuntimeException(self::VERIFY_NULL_DUMMY, 'Extra P2SH stack value should be OP_0');
985
                            }
986
987 30
                            $mainStack->pop();
988 30
                            $mainStack->push($fSuccess ? $this->vchTrue : $this->vchFalse);
989
990 30
                            if ($opCode === Opcodes::OP_CHECKMULTISIGVERIFY) {
991
                                if ($fSuccess) {
992
                                    $mainStack->pop();
993
                                } else {
994
                                    throw new \RuntimeException('OP_CHECKMULTISIG verify');
995
                                }
996
                            }
997 30
                            break;
998
999 30
                        default:
1000 30
                            throw new \RuntimeException('Opcode not found');
1001 30
                    }
1002
1003 900
                    if (count($mainStack) + count($altStack) > 1000) {
1004
                        throw new \RuntimeException('Invalid stack size, exceeds 1000');
1005
                    }
1006 900
                }
1007 1446
            }
1008
1009 1446
            if (!$vfStack->end() === 0) {
1010
                throw new \RuntimeException('Unbalanced conditional at script end');
1011
            }
1012
1013 1446
            return true;
1014 546
        } catch (ScriptRuntimeException $e) {
1015
            // echo "\n Runtime: " . $e->getMessage() . "\n";
1016
            // Failure due to script tags, can access flag: $e->getFailureFlag()
1017 36
            return false;
1018 510
        } catch (\Exception $e) {
1019
            // echo "\n General: " . $e->getMessage()  . PHP_EOL . $e->getTraceAsString();
1020 510
            return false;
1021
        }
1022
    }
1023
}
1024