Completed
Pull Request — master (#200)
by thomas
53:28 queued 50:12
created

Interpreter::checkSequence()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 18
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 18
ccs 0
cts 12
cp 0
rs 9.4286
cc 3
eloc 11
nc 3
nop 1
crap 12
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\Flags;
10
use BitWasp\Bitcoin\Crypto\EcAdapter\Impl\PhpEcc\Key\PublicKey;
11
use BitWasp\Bitcoin\Key\PublicKeyFactory;
12
use BitWasp\Bitcoin\Locktime;
13
use BitWasp\Bitcoin\Script\Classifier\OutputClassifier;
14
use BitWasp\Bitcoin\Script\Opcodes;
15
use BitWasp\Bitcoin\Script\Script;
16
use BitWasp\Bitcoin\Script\ScriptInterface;
17
use BitWasp\Bitcoin\Signature\TransactionSignature;
18
use BitWasp\Bitcoin\Signature\TransactionSignatureFactory;
19
use BitWasp\Bitcoin\Transaction\SignatureHash\SignatureHashInterface;
20
use BitWasp\Bitcoin\Transaction\TransactionInputInterface;
21
use BitWasp\Bitcoin\Transaction\TransactionInterface;
22
use BitWasp\Buffertools\Buffer;
23
24
class Interpreter implements InterpreterInterface
25
{
26
    /**
27
     * @var int|string
28
     */
29
    private $inputToSign;
30
31
    /**
32
     * @var ScriptInterface
33
     */
34
    private $script;
35
36
    /**
37
     * @var TransactionInterface
38
     */
39
    private $transaction;
40
41
    /**
42
     * Position of OP_CODESEPARATOR, for calculating SigHash
43
     * @var int
44
     */
45
    private $hashStartPos;
46
47
    /**
48
     * @var int
49
     */
50
    private $opCount;
51
52
    /**
53
     * @var \BitWasp\Bitcoin\Flags
54
     */
55
    private $flags;
56
57
    /**
58
     * @var EcAdapterInterface
59
     */
60
    private $ecAdapter;
61
62
    /**
63
     * @var \BitWasp\Bitcoin\Math\Math
64
     */
65
    private $math;
66
67
    /**
68
     * @var State
69
     */
70
    private $state;
71
72
    /**
73
     * @var bool
74
     */
75
    private $minimalPush;
76
77
    /**
78
     * @var array
79
     */
80
    private $disabledOps = [
81
        Opcodes::OP_CAT,    Opcodes::OP_SUBSTR, Opcodes::OP_LEFT,  Opcodes::OP_RIGHT,
82
        Opcodes::OP_INVERT, Opcodes::OP_AND,    Opcodes::OP_OR,    Opcodes::OP_XOR,
83
        Opcodes::OP_2MUL,   Opcodes::OP_2DIV,   Opcodes::OP_MUL,   Opcodes::OP_DIV,
84
        Opcodes::OP_MOD,    Opcodes::OP_LSHIFT, Opcodes::OP_RSHIFT
85
    ];
86
87
    /**
88
     * @param EcAdapterInterface $ecAdapter
89
     * @param TransactionInterface $transaction
90
     * @param \BitWasp\Bitcoin\Flags $flags
91
     */
92 762
    public function __construct(EcAdapterInterface $ecAdapter, TransactionInterface $transaction, Flags $flags)
93
    {
94 762
        $this->ecAdapter = $ecAdapter;
95 762
        $this->math = $ecAdapter->getMath();
96 762
        $this->transaction = $transaction;
97 762
        $this->flags = $flags;
98 762
        $this->script = new Script();
99 762
        $this->minimalPush = $this->flags->checkFlags(self::VERIFY_MINIMALDATA) === true;
100 762
        $this->state = new State();
101 762
        $this->vchFalse = new Buffer("", 0, $this->math);
0 ignored issues
show
Bug introduced by
The property vchFalse does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
102 762
        $this->vchTrue = new Buffer("\x01", 1, $this->math);
0 ignored issues
show
Bug introduced by
The property vchTrue does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
103
104 762
        $this->int0 = Number::buffer($this->vchFalse, false, 4, $this->math)->getBuffer();
0 ignored issues
show
Bug introduced by
The property int0 does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
105 762
        $this->int1 = Number::buffer($this->vchTrue, false, 1, $this->math)->getBuffer();
0 ignored issues
show
Bug introduced by
The property int1 does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
106 762
    }
107
108
    /**
109
     * @return State
110
     */
111 6
    public function getStackState()
112
    {
113 6
        return $this->state;
114
    }
115
116
    /**
117
     * @param ScriptInterface $script
118
     * @return $this
119
     */
120 684
    public function setScript(ScriptInterface $script)
121
    {
122 684
        $this->script = $script;
123 684
        return $this;
124
    }
125
126
    /**
127
     * Cast the value to a boolean
128
     *
129
     * @param $value
130
     * @return bool
131
     */
132 432
    public function castToBool(Buffer $value)
133
    {
134 432
        if ($value->getSize() === 0) {
135 72
            return true;
136
        }
137
138
        // Since we're using buffers, lets try ensuring the contents are not 0.
139 360
        return $this->math->cmp($value->getInt(), 0) > 0;
140
    }
141
142
    /**
143
     * @param Buffer $signature
144
     * @return bool
145
     */
146 54
    public function isValidSignatureEncoding(Buffer $signature)
147
    {
148
        try {
149 54
            TransactionSignature::isDERSignature($signature);
150 36
            return true;
151 18
        } catch (SignatureNotCanonical $e) {
1 ignored issue
show
Unused Code introduced by
This catchblock is empty and will swallow any caught exception.

This check looks for ``catch` blocks that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

Empty catch blocks will swallow any caught exception, sometimes causing bugs in your code that are very hard to debug. Consider logging the exception to a debug log or re-throwing it in some way, shape or form.

Loading history...
152
            /* In any case, we will return false outside this block */
153
        }
154
155 18
        return false;
156
    }
157
158
    /**
159
     * @param Buffer $signature
160
     * @return bool
161
     * @throws ScriptRuntimeException
162
     * @throws \Exception
163
     */
164 30
    public function isLowDerSignature(Buffer $signature)
165
    {
166 30
        if (!$this->isValidSignatureEncoding($signature)) {
167 6
            throw new ScriptRuntimeException(self::VERIFY_DERSIG, 'Signature with incorrect encoding');
168
        }
169
170 24
        $binary = $signature->getBinary();
171 24
        $nLenR = ord($binary[3]);
172 24
        $nLenS = ord($binary[5 + $nLenR]);
173 24
        $s = $signature->slice(6 + $nLenR, $nLenS)->getInt();
174
175 24
        return $this->ecAdapter->validateSignatureElement($s, true);
176
    }
177
178
    /**
179
     * Determine whether the sighash byte appended to the signature encodes
180
     * a valid sighash type.
181
     *
182
     * @param Buffer $signature
183
     * @return bool
184
     */
185 36
    public function isDefinedHashtypeSignature(Buffer $signature)
186
    {
187 36
        if ($signature->getSize() === 0) {
188 6
            return false;
189
        }
190
191 30
        $binary = $signature->getBinary();
192 30
        $nHashType = ord(substr($binary, -1)) & (~(SignatureHashInterface::SIGHASH_ANYONECANPAY));
193
194 30
        $math = $this->math;
195 30
        return ! ($math->cmp($nHashType, SignatureHashInterface::SIGHASH_ALL) < 0 || $math->cmp($nHashType, SignatureHashInterface::SIGHASH_SINGLE) > 0);
196
    }
197
198
    /**
199
     * @param Buffer $signature
200
     * @return $this
201
     * @throws \BitWasp\Bitcoin\Exceptions\ScriptRuntimeException
202
     */
203 60
    public function checkSignatureEncoding(Buffer $signature)
204
    {
205 60
        if ($signature->getSize() === 0) {
206 6
            return $this;
207
        }
208
209 54
        if ($this->flags->checkFlags(self::VERIFY_DERSIG | self::VERIFY_LOW_S | self::VERIFY_STRICTENC) && !$this->isValidSignatureEncoding($signature)) {
210 12
            throw new ScriptRuntimeException(self::VERIFY_DERSIG, 'Signature with incorrect encoding');
211 42
        } else if ($this->flags->checkFlags(self::VERIFY_LOW_S) && !$this->isLowDerSignature($signature)) {
212 6
            throw new ScriptRuntimeException(self::VERIFY_LOW_S, 'Signature s element was not low');
213 36
        } else if ($this->flags->checkFlags(self::VERIFY_STRICTENC) && !$this->isDefinedHashtypeSignature($signature)) {
214 6
            throw new ScriptRuntimeException(self::VERIFY_STRICTENC, 'Signature with invalid hashtype');
215
        }
216
217 30
        return $this;
218
    }
219
220
    /**
221
     * @param Buffer $publicKey
222
     * @return $this
223
     * @throws \Exception
224
     */
225 24
    public function checkPublicKeyEncoding(Buffer $publicKey)
226
    {
227 24
        if ($this->flags->checkFlags(self::VERIFY_STRICTENC) && !PublicKey::isCompressedOrUncompressed($publicKey)) {
228 6
            throw new ScriptRuntimeException(self::VERIFY_STRICTENC, 'Public key with incorrect encoding');
229
        }
230
231 18
        return $this;
232
    }
233
234
    /**
235
     * @param $opCode
236
     * @param Buffer $pushData
237
     * @return bool
238
     * @throws \Exception
239
     */
240 6
    public function checkMinimalPush($opCode, Buffer $pushData)
241
    {
242 6
        $pushSize = $pushData->getSize();
243 6
        $binary = $pushData->getBinary();
244
245 6
        if ($pushSize === 0) {
246
            return $opCode === Opcodes::OP_0;
247 6
        } elseif ($pushSize === 1) {
248
            $first = ord($binary[0]);
249
            if ($first >= 1 && $first <= 16) {
250
                return $opCode === (Opcodes::OP_1 + ($first - 1));
251
            } elseif ($first === 0x81) {
252
                return $opCode === Opcodes::OP_1NEGATE;
253
            }
254 6
        } elseif ($pushSize <= 75) {
255 6
            return $opCode === $pushSize;
256
        } elseif ($pushSize <= 255) {
257
            return $opCode === Opcodes::OP_PUSHDATA1;
258
        } elseif ($pushSize <= 65535) {
259
            return $opCode === Opcodes::OP_PUSHDATA2;
260
        }
261
262
        return true;
263
    }
264
265
    /**
266
     * @return $this
267
     * @throws \Exception
268
     */
269 672
    private function checkOpcodeCount()
270
    {
271 672
        if ($this->math->cmp($this->opCount, 201) > 0) {
272 6
            throw new \RuntimeException('Error: Script op code count');
273
        }
274
275 672
        return $this;
276
    }
277
278
    /**
279
     * @param ScriptInterface $script
280
     * @param Buffer $sigBuf
281
     * @param Buffer $keyBuf
282
     * @return bool
283
     * @throws ScriptRuntimeException
284
     * @throws \Exception
285
     */
286 18
    private function checkSig(ScriptInterface $script, Buffer $sigBuf, Buffer $keyBuf)
287
    {
288 18
        $this
289 18
            ->checkSignatureEncoding($sigBuf)
290 12
            ->checkPublicKeyEncoding($keyBuf);
291
292
        try {
293 12
            $txSignature = TransactionSignatureFactory::fromHex($sigBuf->getHex());
294 12
            $publicKey = PublicKeyFactory::fromHex($keyBuf->getHex());
295
296 12
            return $this->ecAdapter->verify(
297 12
                $this
298
                    ->transaction
299 12
                    ->getSignatureHash()
300 12
                    ->calculate($script, $this->inputToSign, $txSignature->getHashType()),
301 12
                $publicKey,
302 12
                $txSignature->getSignature()
303 12
            );
304
        } catch (\Exception $e) {
305
            return false;
306
        }
307
    }
308
309
    /**
310
     * @param int $txLockTime
311
     * @param int $nThreshold
312
     * @param \BitWasp\Bitcoin\Script\Interpreter\Number $lockTime
313
     * @return bool
314
     */
315
    private function verifyLockTime($txLockTime, $nThreshold, Number $lockTime)
316
    {
317
        $nTime = $lockTime->getInt();
318
        if (($this->math->cmp($txLockTime, $nThreshold) < 0 && $this->math->cmp($nTime, $nThreshold) < 0) ||
319
            ($this->math->cmp($txLockTime, $nThreshold) >= 0 && $this->math->cmp($nTime, $nThreshold) >= 0)
320
        ) {
321
            return false;
322
        }
323
324
        return $this->math->cmp($nTime, $txLockTime) >= 0;
325
    }
326
327
    /**
328
     * @param \BitWasp\Bitcoin\Script\Interpreter\Number $lockTime
329
     * @return bool
330
     */
331
    private function checkLockTime(Number $lockTime)
332
    {
333
        if ($this->transaction->getInput($this->inputToSign)->isFinal()) {
334
            return false;
335
        }
336
337
        return $this->verifyLockTime($this->transaction->getLockTime(), Locktime::BLOCK_MAX, $lockTime);
338
    }
339
340
    /**
341
     * @param Number $sequence
342
     * @return bool
343
     */
344
    private function checkSequence(Number $sequence)
345
    {
346
        $txSequence = $this->transaction->getInput($this->inputToSign)->getSequence();
347
        if ($this->transaction->getVersion() < 2) {
348
            return false;
349
        }
350
351
        if ($this->math->cmp($this->math->bitwiseAnd($txSequence, TransactionInputInterface::SEQUENCE_LOCKTIME_DISABLE_FLAG), 0) !== 0) {
352
            return 0;
353
        }
354
355
        $mask = $this->math->bitwiseOr(TransactionInputInterface::SEQUENCE_LOCKTIME_TYPE_FLAG, TransactionInputInterface::SEQUENCE_LOCKTIME_MASK);
356
        return $this->verifyLockTime(
357
            $this->math->bitwiseAnd($txSequence, $mask),
358
            TransactionInputInterface::SEQUENCE_LOCKTIME_TYPE_FLAG,
359
            Number::int($this->math->bitwiseAnd($sequence->getInt(), $mask))
360
        );
361
    }
362
363
    /**
364
     * @param ScriptInterface $scriptSig
365
     * @param ScriptInterface $scriptPubKey
366
     * @param int $nInputToSign
367
     * @return bool
368
     * @throws \Exception
369
     */
370 684
    public function verify(ScriptInterface $scriptSig, ScriptInterface $scriptPubKey, $nInputToSign)
371
    {
372 684
        $this->inputToSign = $nInputToSign;
373 684
        if (!$this->setScript($scriptSig)->run()) {
374
            return false;
375
        }
376
377 684
        $mainStack = $this->state->getMainStack();
378 684
        $stackCopy = new Stack;
379 684
        if ($this->flags->checkFlags(self::VERIFY_P2SH)) {
380 156
            $stackCopy = $this->state->cloneMainStack();
381 156
        }
382
383 684
        if (!$this->setScript($scriptPubKey)->run()) {
384 258
            return false;
385
        }
386
387 426
        if ($mainStack->isEmpty()) {
388
            return false;
389
        }
390
391 426
        if (false === $this->castToBool($mainStack[-1])) {
392
            return false;
393
        }
394
395 426
        $verifier = new OutputClassifier($scriptPubKey);
396
397 426
        if ($this->flags->checkFlags(self::VERIFY_P2SH) && $verifier->isPayToScriptHash()) {
398 6
            if (!$scriptSig->isPushOnly()) {
399
                return false;
400
            }
401
402
            // Restore mainStack to how it was after evaluating scriptSig
403 6
            $mainStack = $this->state->restoreMainStack($stackCopy)->getMainStack();
404 6
            if ($mainStack->isEmpty()) {
405
                return false;
406
            }
407
408
            // Load redeemscript as the scriptPubKey
409 6
            $scriptPubKey = new Script($mainStack->bottom());
410 6
            $mainStack->pop();
411
412 6
            if (!$this->setScript($scriptPubKey)->run()) {
413
                return false;
414
            }
415 6
        }
416
417 426
        return true;
418
    }
419
420
    /**
421
     * @return bool
422
     */
423 684
    private function checkExec()
424
    {
425 684
        $vfStack = $this->state->getVfStack();
426 684
        $c = 0;
427 684
        $len = $vfStack->end();
428 684
        for ($i = 0; $i < $len; $i++) {
429
            if ($vfStack[0 - $len - $i] === true) {
430
                $c++;
431
            }
432
        }
433 684
        return !(bool)$c;
434
    }
435
436
    /**
437
     * @return bool
438
     */
439 684
    private function run()
440
    {
441 684
        $math = $this->math;
442
443 684
        $flags = $this->flags;
444 684
        $mainStack = $this->state->getMainStack();
445 684
        $altStack = $this->state->getAltStack();
446 684
        $vfStack = $this->state->getVfStack();
447
448 684
        $this->hashStartPos = 0;
449 684
        $this->opCount = 0;
450 684
        $parser = $this->script->getScriptParser();
451
452 684
        if ($this->script->getBuffer()->getSize() > 10000) {
453
            return false;
454
        }
455
456
        try {
457 684
            foreach ($parser as $exec) {
458 684
                $opCode = $exec->getOp();
459 684
                $pushData = $exec->getData();
460 684
                $fExec = $this->checkExec();
461
462
                // If pushdata was written to,
463 684
                if ($exec->isPush() && $exec->getDataSize() > InterpreterInterface::MAX_SCRIPT_ELEMENT_SIZE) {
464
                    throw new \RuntimeException('Error - push size');
465
                }
466
467
                // OP_RESERVED should not count towards opCount
468 684
                if ($opCode > Opcodes::OP_16 && ++$this->opCount) {
469 672
                    $this->checkOpcodeCount();
470 672
                }
471
472 684
                if (in_array($opCode, $this->disabledOps, true)) {
473 12
                    throw new \RuntimeException('Disabled Opcode');
474
                }
475
476 684
                if ($fExec && $exec->isPush()) {
477
                    // In range of a pushdata opcode
478 426
                    if ($this->minimalPush && !$this->checkMinimalPush($opCode, $pushData)) {
479 6
                        throw new ScriptRuntimeException(self::VERIFY_MINIMALDATA, 'Minimal pushdata required');
480
                    }
481
482 420
                    $mainStack->push($pushData);
483
                    // echo " - [pushed '" . $pushData->getHex() . "']\n";
484 678
                } elseif ($fExec || ($opCode !== Opcodes::OP_IF && $opCode !== Opcodes::OP_ENDIF)) {
485
                    // echo "OPCODE - " . $this->script->getOpCodes()->getOp($opCode) . "\n";
486
                    switch ($opCode) {
487 660
                        case Opcodes::OP_1NEGATE:
488 660
                        case Opcodes::OP_1:
489 660
                        case Opcodes::OP_2:
490 660
                        case Opcodes::OP_3:
491 660
                        case Opcodes::OP_4:
492 660
                        case Opcodes::OP_5:
493 660
                        case Opcodes::OP_6:
494 660
                        case Opcodes::OP_7:
495 660
                        case Opcodes::OP_8:
496 660
                        case Opcodes::OP_9:
497 660
                        case Opcodes::OP_10:
498 660
                        case Opcodes::OP_11:
499 660
                        case Opcodes::OP_12:
500 660
                        case Opcodes::OP_13:
501 660
                        case Opcodes::OP_14:
502 660
                        case Opcodes::OP_15:
503 660
                        case Opcodes::OP_16:
504 192
                            $num = $opCode - (Opcodes::OP_1 - 1);
505 192
                            $mainStack->push(Number::int($num)->getBuffer());
506 192
                            break;
507
508 660
                        case Opcodes::OP_CHECKLOCKTIMEVERIFY:
509
                            if (!$this->flags->checkFlags(self::VERIFY_CHECKLOCKTIMEVERIFY)) {
510
                                if ($this->flags->checkFlags(self::VERIFY_DISCOURAGE_UPGRADABLE_NOPS)) {
511
                                    throw new ScriptRuntimeException(self::VERIFY_DISCOURAGE_UPGRADABLE_NOPS, 'Upgradable NOP found - this is discouraged');
512
                                }
513
                                break;
514
                            }
515
516
                            if ($mainStack->isEmpty()) {
517
                                throw new \RuntimeException('Invalid stack operation - CLTV');
518
                            }
519
520
                            $lockTime = Number::buffer($mainStack[-1], $this->minimalPush, 5, $math);
521
                            if (!$this->checkLockTime($lockTime)) {
522
                                throw new ScriptRuntimeException(self::VERIFY_CHECKLOCKTIMEVERIFY, 'Unsatisfied locktime');
523
                            }
524
525
                            break;
526
527 660
                        case Opcodes::OP_CHECKSEQUENCEVERIFY:
528
                            if (!$this->flags->checkFlags(self::VERIFY_CHECKSEQUENCEVERIFY)) {
529
                                if ($this->flags->checkFlags(self::VERIFY_DISCOURAGE_UPGRADABLE_NOPS)) {
530
                                    throw new ScriptRuntimeException(self::VERIFY_DISCOURAGE_UPGRADABLE_NOPS, 'Upgradable NOP found - this is discouraged');
531
                                }
532
                                break;
533
                            }
534
535
                            if ($mainStack->isEmpty()) {
536
                                throw new \RuntimeException('Invalid stack operation - CSV');
537
                            }
538
539
                            $sequence = Number::buffer($mainStack[-1], $this->minimalPush, 5, $math)->getInt();
540
541
                            if ($math->cmp($sequence, 0) < 0) {
542
                                throw new ScriptRuntimeException(self::VERIFY_CHECKSEQUENCEVERIFY, 'Negative locktime');
543
                            }
544
545
                            if ($math->cmp($math->bitwiseAnd($sequence, TransactionInputInterface::SEQUENCE_LOCKTIME_DISABLE_FLAG), '0') !== 0) {
546
                                break;
547
                            }
548
549
                            if (!$this->checkSequence($sequence)) {
0 ignored issues
show
Documentation introduced by
$sequence is of type integer, but the function expects a object<BitWasp\Bitcoin\Script\Interpreter\Number>.

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...
550
                                throw new ScriptRuntimeException(self::VERIFY_CHECKSEQUENCEVERIFY, 'Unsatisfied locktime');
551
                            }
552
                            break;
553
554 660
                        case Opcodes::OP_NOP1:
555 660
                        case Opcodes::OP_NOP4:
556 660
                        case Opcodes::OP_NOP5:
557 660
                        case Opcodes::OP_NOP6:
558 660
                        case Opcodes::OP_NOP7:
559 660
                        case Opcodes::OP_NOP8:
560 660
                        case Opcodes::OP_NOP9:
561 660
                        case Opcodes::OP_NOP10:
562 6
                            if ($flags->checkFlags(self::VERIFY_DISCOURAGE_UPGRADABLE_NOPS)) {
563 6
                                throw new ScriptRuntimeException(self::VERIFY_DISCOURAGE_UPGRADABLE_NOPS, 'Upgradable NOP found - this is discouraged');
564
                            }
565
                            break;
566
567 654
                        case Opcodes::OP_NOP:
568 12
                            break;
569
570 642
                        case Opcodes::OP_IF:
571 642
                        case Opcodes::OP_NOTIF:
572
                            // <expression> if [statements] [else [statements]] endif
573 18
                            $value = false;
574 18
                            if ($fExec) {
575 18
                                if ($mainStack->isEmpty()) {
576 6
                                    throw new \RuntimeException('Unbalanced conditional');
577
                                }
578
                                // todo
579 12
                                $buffer = Number::buffer($mainStack->pop(), $this->minimalPush)->getBuffer();
580 12
                                $value = $this->castToBool($buffer);
581 12
                                if ($opCode === Opcodes::OP_NOTIF) {
582 6
                                    $value = !$value;
583 6
                                }
584 12
                            }
585 12
                            $vfStack->push($value ? $this->vchTrue : $this->vchFalse);
586 12
                            break;
587
588 636
                        case Opcodes::OP_ELSE:
589 18
                            if ($vfStack->isEmpty()) {
590 6
                                throw new \RuntimeException('Unbalanced conditional');
591
                            }
592 12
                            $vfStack[-1] = !$vfStack->end() ? $this->vchTrue : $this->vchFalse;
593 12
                            break;
594
595 630
                        case Opcodes::OP_ENDIF:
596 18
                            if ($vfStack->isEmpty()) {
597 6
                                throw new \RuntimeException('Unbalanced conditional');
598
                            }
599 12
                            break;
600
601 624
                        case Opcodes::OP_VERIFY:
602 24
                            if ($mainStack->isEmpty()) {
603 6
                                throw new \RuntimeException('Invalid stack operation');
604
                            }
605 18
                            $value = $this->castToBool($mainStack[-1]);
606 18
                            if (!$value) {
607 6
                                throw new \RuntimeException('Error: verify');
608
                            }
609 12
                            $mainStack->pop();
610 12
                            break;
611
612 600
                        case Opcodes::OP_RESERVED:
613
                            // todo
614 12
                            break;
615
616 588
                        case Opcodes::OP_TOALTSTACK:
617 18
                            if ($mainStack->isEmpty()) {
618 6
                                throw new \RuntimeException('Invalid stack operation OP_TOALTSTACK');
619
                            }
620 12
                            $altStack->push($mainStack->pop());
621 12
                            break;
622
623 582
                        case Opcodes::OP_FROMALTSTACK:
624 12
                            if ($altStack->isEmpty()) {
625 6
                                throw new \RuntimeException('Invalid alt-stack operation OP_FROMALTSTACK');
626
                            }
627 6
                            $mainStack->push($altStack->pop());
628 6
                            break;
629
630 576
                        case Opcodes::OP_IFDUP:
631
                            // If top value not zero, duplicate it.
632 12
                            if ($mainStack->isEmpty()) {
633 6
                                throw new \RuntimeException('Invalid stack operation OP_IFDUP');
634
                            }
635 6
                            $vch = $mainStack[-1];
636 6
                            if ($this->castToBool($vch)) {
637 6
                                $mainStack->push($vch);
638 6
                            }
639 6
                            break;
640
641 570
                        case Opcodes::OP_DEPTH:
642 72
                            $num = count($mainStack);
643 72
                            if ($num === 0) {
644 24
                                $depth = $this->vchFalse;
645 24
                            } else {
646 54
                                $depth = Number::int($num)->getBuffer();
647
                            }
648
649 72
                            $mainStack->push($depth);
650 72
                            break;
651
652 570
                        case Opcodes::OP_DROP:
653 6
                            if ($mainStack->isEmpty()) {
654 6
                                throw new \RuntimeException('Invalid stack operation OP_DROP');
655
                            }
656
                            $mainStack->pop();
657
                            break;
658
659 564
                        case Opcodes::OP_DUP:
660 18
                            if ($mainStack->isEmpty()) {
661 6
                                throw new \RuntimeException('Invalid stack operation OP_DUP');
662
                            }
663 12
                            $vch = $mainStack[-1];
664 12
                            $mainStack->push($vch);
665 12
                            break;
666
667 558
                        case Opcodes::OP_NIP:
668 18
                            if (count($mainStack) < 2) {
669 6
                                throw new \RuntimeException('Invalid stack operation OP_NIP');
670
                            }
671 12
                            unset($mainStack[-2]);
672 12
                            break;
673
674 552
                        case Opcodes::OP_OVER:
675 18
                            if (count($mainStack) < 2) {
676 6
                                throw new \RuntimeException('Invalid stack operation OP_OVER');
677
                            }
678 12
                            $vch = $mainStack[-2];
679 12
                            $mainStack->push($vch);
680 12
                            break;
681
    
682 546
                        case Opcodes::OP_ROT:
683 12
                            if (count($mainStack) < 3) {
684 6
                                throw new \RuntimeException('Invalid stack operation OP_ROT');
685
                            }
686 6
                            $mainStack->swap(-3, -2);
687 6
                            $mainStack->swap(-2, -1);
688 6
                            break;
689
690 540
                        case Opcodes::OP_SWAP:
691 12
                            if (count($mainStack) < 2) {
692 6
                                throw new \RuntimeException('Invalid stack operation OP_SWAP');
693
                            }
694 6
                            $mainStack->swap(-2, -1);
695 6
                            break;
696
697 534
                        case Opcodes::OP_TUCK:
698 12
                            if (count($mainStack) < 2) {
699 6
                                throw new \RuntimeException('Invalid stack operation OP_TUCK');
700
                            }
701 6
                            $vch = $mainStack[-1];
702 6
                            $mainStack->add(count($mainStack) - 1 - 2, $vch);
703
                            break;
704
705 522
                        case Opcodes::OP_PICK:
706 522
                        case Opcodes::OP_ROLL:
707 24
                            if (count($mainStack) < 2) {
708 6
                                throw new \RuntimeException('Invalid stack operation OP_PICK');
709
                            }
710
711 18
                            $n = Number::buffer($mainStack[-1], $this->minimalPush, 4)->getInt();
712 18
                            $mainStack->pop();
713 18
                            if ($math->cmp($n, 0) < 0 || $math->cmp($n, count($mainStack)) >= 0) {
714 6
                                throw new \RuntimeException('Invalid stack operation OP_PICK');
715
                            }
716
717 12
                            $pos = (int) $math->sub($math->sub(0, $n), 1);
718 12
                            $vch = $mainStack[$pos];
719 12
                            if ($opCode === Opcodes::OP_ROLL) {
720 6
                                unset($mainStack[$pos]);
721 6
                            }
722 12
                            $mainStack->push($vch);
723 12
                            break;
724
725 510
                        case Opcodes::OP_2DROP:
726 12
                            if (count($mainStack) < 2) {
727 6
                                throw new \RuntimeException('Invalid stack operation OP_2DROP');
728
                            }
729 6
                            $mainStack->pop();
730 6
                            $mainStack->pop();
731 6
                            break;
732
733 504
                        case Opcodes::OP_2DUP:
734 18
                            if (count($mainStack) < 2) {
735 6
                                throw new \RuntimeException('Invalid stack operation OP_2DUP');
736
                            }
737 12
                            $string1 = $mainStack[-2];
738 12
                            $string2 = $mainStack[-1];
739 12
                            $mainStack->push($string1);
740 12
                            $mainStack->push($string2);
741 12
                            break;
742
743 498
                        case Opcodes::OP_3DUP:
744 18
                            if (count($mainStack) < 3) {
745 6
                                throw new \RuntimeException('Invalid stack operation OP_3DUP');
746
                            }
747 12
                            $string1 = $mainStack[-3];
748 12
                            $string2 = $mainStack[-2];
749 12
                            $string3 = $mainStack[-1];
750 12
                            $mainStack->push($string1);
751 12
                            $mainStack->push($string2);
752 12
                            $mainStack->push($string3);
753 12
                            break;
754
755 492
                        case Opcodes::OP_2OVER:
756 18
                            if (count($mainStack) < 4) {
757 6
                                throw new \RuntimeException('Invalid stack operation OP_2OVER');
758
                            }
759 12
                            $string1 = $mainStack[-4];
760 12
                            $string2 = $mainStack[-3];
761 12
                            $mainStack->push($string1);
762 12
                            $mainStack->push($string2);
763 12
                            break;
764
765 486
                        case Opcodes::OP_2ROT:
766 12
                            if (count($mainStack) < 6) {
767 6
                                throw new \RuntimeException('Invalid stack operation OP_2ROT');
768
                            }
769 6
                            $string1 = $mainStack[-6];
770 6
                            $string2 = $mainStack[-5];
771 6
                            unset($mainStack[-6], $mainStack[-5]);
772 6
                            $mainStack->push($string1);
773 6
                            $mainStack->push($string2);
774 6
                            break;
775
776 480
                        case Opcodes::OP_2SWAP:
777 12
                            if (count($mainStack) < 4) {
778 6
                                throw new \RuntimeException('Invalid stack operation OP_2SWAP');
779
                            }
780 6
                            $mainStack->swap(-3, -1);
781 6
                            $mainStack->swap(-4, -2);
782 6
                            break;
783
784 474
                        case Opcodes::OP_SIZE:
785 12
                            if ($mainStack->isEmpty()) {
786 6
                                throw new \RuntimeException('Invalid stack operation OP_SIZE');
787
                            }
788
                            // todo: Int sizes?
789 6
                            $vch = $mainStack[-1];
790 6
                            $mainStack->push(Number::int($vch->getSize())->getBuffer());
791 6
                            break;
792
793 468
                        case Opcodes::OP_EQUAL:
794 468
                        case Opcodes::OP_EQUALVERIFY:
795 396
                            if (count($mainStack) < 2) {
796 6
                                throw new \RuntimeException('Invalid stack operation OP_EQUAL');
797
                            }
798 390
                            $vch1 = $mainStack[-2];
799 390
                            $vch2 = $mainStack[-1];
800
801 390
                            $equal = ($vch1->getBinary() === $vch2->getBinary());
802
803 390
                            $mainStack->pop();
804 390
                            $mainStack->pop();
805 390
                            $mainStack->push(($equal ? $this->vchTrue : $this->vchFalse));
806 390
                            if ($opCode === Opcodes::OP_EQUALVERIFY) {
807 114
                                if ($equal) {
808 102
                                    $mainStack->pop();
809 102
                                } else {
810 12
                                    throw new \RuntimeException('Error EQUALVERIFY');
811
                                }
812 102
                            }
813
814 378
                            break;
815
816
                        // Arithmetic operations
817 282
                        case $opCode >= Opcodes::OP_1ADD && $opCode <= Opcodes::OP_0NOTEQUAL:
818 48
                            if ($mainStack->isEmpty()) {
819 6
                                throw new \Exception('Invalid stack operation 1ADD-OP_0NOTEQUAL');
820
                            }
821
822 42
                            $num = Number::buffer($mainStack[-1], $this->minimalPush)->getInt();
823
824 42
                            if ($opCode === Opcodes::OP_1ADD) {
825 6
                                $num = $math->add($num, '1');
826 42
                            } elseif ($opCode === Opcodes::OP_1SUB) {
827 6
                                $num = $math->sub($num, '1');
828 36
                            } elseif ($opCode === Opcodes::OP_2MUL) {
829
                                $num = $math->mul(2, $num);
830 30
                            } elseif ($opCode === Opcodes::OP_NEGATE) {
831
                                $num = $math->sub(0, $num);
832 30
                            } elseif ($opCode === Opcodes::OP_ABS) {
833
                                if ($math->cmp($num, '0') < 0) {
834
                                    $num = $math->sub(0, $num);
835
                                }
836 30
                            } elseif ($opCode === Opcodes::OP_NOT) {
837 18
                                $num = (int) $math->cmp($num, '0') === 0;
838 18
                            } else {
839
                                // is OP_0NOTEQUAL
840 12
                                $num = (int) ($math->cmp($num, '0') !== 0);
841
                            }
842
843 42
                            $mainStack->pop();
844
845 42
                            $buffer = Number::int($num)->getBuffer();
846
847 42
                            $mainStack->push($buffer);
848 42
                            break;
849
850 234
                        case $opCode >= Opcodes::OP_ADD && $opCode <= Opcodes::OP_MAX:
851 150
                            if (count($mainStack) < 2) {
852 24
                                throw new \Exception('Invalid stack operation (OP_ADD - OP_MAX)');
853
                            }
854
855 126
                            $num1 = Number::buffer($mainStack[-2], $this->minimalPush)->getInt();
856 126
                            $num2 = Number::buffer($mainStack[-1], $this->minimalPush)->getInt();
857
858 126
                            if ($opCode === Opcodes::OP_ADD) {
859 6
                                $num = $math->add($num1, $num2);
860 126
                            } else if ($opCode === Opcodes::OP_SUB) {
861 6
                                $num = $math->sub($num1, $num2);
862 120
                            } else if ($opCode === Opcodes::OP_BOOLAND) {
863 12
                                $num = $math->cmp($num1, $this->int0->getInt()) !== 0 && $math->cmp($num2, $this->int0->getInt()) !== 0;
864 114
                            } else if ($opCode === Opcodes::OP_BOOLOR) {
865 18
                                $num = $math->cmp($num1, $this->int0->getInt()) !== 0 || $math->cmp($num2, $this->int0->getInt()) !== 0;
866 102
                            } elseif ($opCode === Opcodes::OP_NUMEQUAL) {
867 18
                                $num = $math->cmp($num1, $num2) === 0;
868 84
                            } elseif ($opCode === Opcodes::OP_NUMEQUALVERIFY) {
869
                                $num = $math->cmp($num1, $num2) === 0;
870 66
                            } elseif ($opCode === Opcodes::OP_NUMNOTEQUAL) {
871 6
                                $num = $math->cmp($num1, $num2) !== 0;
872 66
                            } elseif ($opCode === Opcodes::OP_LESSTHAN) {
873 12
                                $num = $math->cmp($num1, $num2) < 0;
874 60
                            } elseif ($opCode === Opcodes::OP_GREATERTHAN) {
875 12
                                $num = $math->cmp($num1, $num2) > 0;
876 48
                            } elseif ($opCode === Opcodes::OP_LESSTHANOREQUAL) {
877 12
                                $num = $math->cmp($num1, $num2) <= 0;
878 36
                            } elseif ($opCode === Opcodes::OP_GREATERTHANOREQUAL) {
879 12
                                $num = $math->cmp($num1, $num2) >= 0;
880 24
                            } elseif ($opCode === Opcodes::OP_MIN) {
881 6
                                $num = ($math->cmp($num1, $num2) <= 0) ? $num1 : $num2;
882 6
                            } else {
883 6
                                $num = ($math->cmp($num1, $num2) >= 0) ? $num1 : $num2;
884
                            }
885
886 126
                            $mainStack->pop();
887 126
                            $mainStack->pop();
888 126
                            $buffer = Number::int($num)->getBuffer();
889 126
                            $mainStack->push($buffer);
890
891 126
                            if ($opCode === Opcodes::OP_NUMEQUALVERIFY) {
892
                                if ($this->castToBool($mainStack[-1])) {
893
                                    $mainStack->pop();
894
                                } else {
895
                                    throw new \RuntimeException('NUM EQUAL VERIFY error');
896
                                }
897
                            }
898 126
                            break;
899
900 84
                        case Opcodes::OP_WITHIN:
901 12
                            if (count($mainStack) < 3) {
902 6
                                throw new \RuntimeException('Invalid stack operation');
903
                            }
904
905 6
                            $num1 = Number::buffer($mainStack[-3], $this->minimalPush)->getInt();
906 6
                            $num2 = Number::buffer($mainStack[-2], $this->minimalPush)->getInt();
907 6
                            $num3 = Number::buffer($mainStack[-1], $this->minimalPush)->getInt();
908
909 6
                            $value = $math->cmp($num2, $num1) <= 0 && $math->cmp($num1, $num3) < 0;
910 6
                            $mainStack->pop();
911 6
                            $mainStack->pop();
912 6
                            $mainStack->pop();
913 6
                            $mainStack->push($value ? $this->vchFalse : $this->vchTrue);
914 6
                            break;
915
916
                        // Hash operation
917 72
                        case Opcodes::OP_RIPEMD160:
918 72
                        case Opcodes::OP_SHA1:
919 72
                        case Opcodes::OP_SHA256:
920 72
                        case Opcodes::OP_HASH160:
921 72
                        case Opcodes::OP_HASH256:
922 48
                            if ($mainStack->isEmpty()) {
923 6
                                throw new \RuntimeException('Invalid stack operation');
924
                            }
925
926 42
                            $buffer = $mainStack[-1];
927 42
                            if ($opCode === Opcodes::OP_RIPEMD160) {
928 6
                                $hash = Hash::ripemd160($buffer);
929 42
                            } elseif ($opCode === Opcodes::OP_SHA1) {
930 6
                                $hash = Hash::sha1($buffer);
931 36
                            } elseif ($opCode === Opcodes::OP_SHA256) {
932 6
                                $hash = Hash::sha256($buffer);
933 30
                            } elseif ($opCode === Opcodes::OP_HASH160) {
934 18
                                $hash = Hash::sha256ripe160($buffer);
935 18
                            } else {
936 6
                                $hash = Hash::sha256d($buffer);
937
                            }
938
939 42
                            $mainStack->pop();
940 42
                            $mainStack->push($hash);
941 42
                            break;
942
943 30
                        case Opcodes::OP_CODESEPARATOR:
944
                            $this->hashStartPos = $parser->getPosition();
945
                            break;
946
947 30
                        case Opcodes::OP_CHECKSIG:
948 30
                        case Opcodes::OP_CHECKSIGVERIFY:
949 24
                            if (count($mainStack) < 2) {
950 6
                                throw new \RuntimeException('Invalid stack operation');
951
                            }
952
953 18
                            $vchPubKey = $mainStack[-1];
954 18
                            $vchSig = $mainStack[-2];
955
956 18
                            $scriptCode = new Script($this->script->getBuffer()->slice($this->hashStartPos));
957 18
                            $success = $this->checkSig($scriptCode, $vchSig, $vchPubKey);
958
959 12
                            $mainStack->pop();
960 12
                            $mainStack->pop();
961 12
                            $mainStack->push($success ? $this->vchTrue : $this->vchFalse);
962
963 12
                            if ($opCode === Opcodes::OP_CHECKSIGVERIFY) {
964
                                if ($success) {
965
                                    $mainStack->pop();
966
                                } else {
967
                                    throw new \RuntimeException('Checksig verify');
968
                                }
969
                            }
970 12
                            break;
971
972 6
                        case Opcodes::OP_CHECKMULTISIG:
973 6
                        case Opcodes::OP_CHECKMULTISIGVERIFY:
974
                            $i = 1;
975
                            if (count($mainStack) < $i) {
976
                                throw new \RuntimeException('Invalid stack operation');
977
                            }
978
979
                            $keyCount = Number::buffer($mainStack[-$i], $this->minimalPush)->getInt();
980
                            if ($math->cmp($keyCount, 0) < 0 || $math->cmp($keyCount, 20) > 0) {
981
                                throw new \RuntimeException('OP_CHECKMULTISIG: Public key count exceeds 20');
982
                            }
983
                            $this->opCount += $keyCount;
984
                            $this->checkOpcodeCount();
985
986
                            // Extract positions of the keys, and signatures, from the stack.
987
                            $ikey = ++$i;
988
                            $i += $keyCount; /** @var int $i */
989
                            if (count($mainStack) < $i) {
990
                                throw new \RuntimeException('Invalid stack operation');
991
                            }
992
993
                            $sigCount = Number::buffer($mainStack[-$i], $this->minimalPush)->getInt();
994
                            if ($math->cmp($sigCount, 0) < 0 || $math->cmp($sigCount, $keyCount) > 0) {
995
                                throw new \RuntimeException('Invalid Signature count');
996
                            }
997
                            $isig = ++$i;
998
                            $i += $sigCount;
999
1000
                            // Extract the script since the last OP_CODESEPARATOR
1001
                            $scriptCode = new Script($this->script->getBuffer()->slice($this->hashStartPos));
1002
1003
                            $fSuccess = true;
1004
                            while ($fSuccess && $sigCount > 0) {
1005
                                // Fetch the signature and public key
1006
                                $sig = $mainStack[-$isig];
1007
                                $pubkey = $mainStack[-$ikey];
1008
1009
                                // Erase the signature and public key.
1010
                                unset($mainStack[-$isig], $mainStack[-$ikey]);
1011
1012
                                // Decrement $i, since we are consuming stack values.
1013
                                $i -= 2;
1014
1015
                                if ($this->checkSig($scriptCode, $sig, $pubkey)) {
1016
                                    $isig++;
1017
                                    $sigCount--;
1018
                                }
1019
1020
                                $ikey++;
1021
                                $keyCount--;
1022
1023
                                // If there are more signatures left than keys left,
1024
                                // then too many signatures have failed. Exit early,
1025
                                // without checking any further signatures.
1026
                                if ($sigCount > $keyCount) {
1027
                                    $fSuccess = false;
1028
                                }
1029
                            }
1030
1031
                            while ($i-- > 1) {
1032
                                $mainStack->pop();
1033
                            }
1034
1035
                            // A bug causes CHECKMULTISIG to consume one extra argument
1036
                            // whose contents were not checked in any way.
1037
                            //
1038
                            // Unfortunately this is a potential source of mutability,
1039
                            // so optionally verify it is exactly equal to zero prior
1040
                            // to removing it from the stack.
1041
                            if ($mainStack->isEmpty()) {
1042
                                throw new \RuntimeException('Invalid stack operation');
1043
                            }
1044
1045
                            if ($flags->checkFlags(self::VERIFY_NULL_DUMMY) && $mainStack[-1]->getSize()) {
1046
                                throw new ScriptRuntimeException(self::VERIFY_NULL_DUMMY, 'Extra P2SH stack value should be OP_0');
1047
                            }
1048
1049
                            $mainStack->pop();
1050
                            $mainStack->push($fSuccess ? $this->vchTrue : $this->vchFalse);
1051
1052
                            if ($opCode === Opcodes::OP_CHECKMULTISIGVERIFY) {
1053
                                if ($fSuccess) {
1054
                                    $mainStack->pop();
1055
                                } else {
1056
                                    throw new \RuntimeException('OP_CHECKMULTISIG verify');
1057
                                }
1058
                            }
1059
                            break;
1060
1061 6
                        default:
1062 6
                            throw new \RuntimeException('Opcode not found');
1063 6
                    }
1064
1065 426
                    if (count($mainStack) + count($altStack) > 1000) {
1066
                        throw new \RuntimeException('Invalid stack size, exceeds 1000');
1067
                    }
1068 426
                }
1069 684
            }
1070
1071 684
            if (!$vfStack->end() === 0) {
1072
                throw new \RuntimeException('Unbalanced conditional at script end');
1073
            }
1074
1075 684
            return true;
1076 258
        } catch (ScriptRuntimeException $e) {
1077
            // echo "\n Runtime: " . $e->getMessage() . "\n";
1078
            // Failure due to script tags, can access flag: $e->getFailureFlag()
1079 18
            return false;
1080 240
        } catch (\Exception $e) {
1081
            // echo "\n General: " . $e->getMessage() ;
1082 240
            return false;
1083
        }
1084
    }
1085
}
1086