Completed
Pull Request — master (#593)
by thomas
15:02
created

CheckSequenceVerify   A

Complexity

Total Complexity 13

Size/Duplication

Total Lines 89
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 4

Test Coverage

Coverage 17.86%

Importance

Changes 0
Metric Value
dl 0
loc 89
ccs 5
cts 28
cp 0.1786
rs 10
c 0
b 0
f 0
wmc 13
lcom 1
cbo 4

6 Methods

Rating   Name   Duplication   Size   Complexity  
A fromScript() 0 4 1
A isRelativeToBlock() 0 8 2
A isDisabled() 0 4 1
A __construct() 0 12 3
B fromDecodedScript() 0 22 5
A getRelativeLockTime() 0 4 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace BitWasp\Bitcoin\Transaction\Factory\ScriptInfo;
6
7
use BitWasp\Bitcoin\Locktime;
8
use BitWasp\Bitcoin\Script\Interpreter\Number;
9
use BitWasp\Bitcoin\Script\Opcodes;
10
use BitWasp\Bitcoin\Script\Parser\Operation;
11
use BitWasp\Bitcoin\Script\ScriptInterface;
12
use BitWasp\Bitcoin\Transaction\TransactionInput;
13
14
class CheckSequenceVerify
15
{
16
    /**
17
     * @var int
18
     */
19
    private $relativeTimeLock;
20
21
    /**
22
     * CheckLocktimeVerify constructor.
23
     * @param int $relativeTimeLock
24
     */
25
    public function __construct(int $relativeTimeLock)
26
    {
27
        if ($relativeTimeLock < 0) {
28
            throw new \RuntimeException("relative locktime cannot be negative");
29
        }
30
31
        if ($relativeTimeLock > Locktime::INT_MAX) {
32
            throw new \RuntimeException("nLockTime exceeds maximum value");
33
        }
34
35
        $this->relativeTimeLock = $relativeTimeLock;
36
    }
37
38
    /**
39
     * @param Operation[] $chunks
40
     * @param bool $fMinimal
41
     * @return static
42
     */
43 3
    public static function fromDecodedScript(array $chunks, $fMinimal = false): self
44
    {
45 3
        if (count($chunks) !== 3) {
46 3
            throw new \RuntimeException("Invalid number of items for CSV");
47
        }
48
49 2
        if (!$chunks[0]->isPush()) {
50 2
            throw new \InvalidArgumentException('CSV script had invalid value for time');
51
        }
52
53
        if ($chunks[1]->getOp() !== Opcodes::OP_CHECKSEQUENCEVERIFY) {
54
            throw new \InvalidArgumentException('CSV script invalid opcode');
55
        }
56
57
        if ($chunks[2]->getOp() !== Opcodes::OP_DROP) {
58
            throw new \InvalidArgumentException('CSV script invalid opcode');
59
        }
60
61
        $numLockTime = Number::buffer($chunks[0]->getData(), $fMinimal, 5);
62
63
        return new static((int) $numLockTime->getInt());
64
    }
65
66
    /**
67
     * @param ScriptInterface $script
68
     * @return CheckSequenceVerify
69
     */
70
    public static function fromScript(ScriptInterface $script): self
71
    {
72
        return static::fromDecodedScript($script->getScriptParser()->decode());
73
    }
74
75
    /**
76
     * @return int
77
     */
78
    public function getRelativeLockTime(): int
79
    {
80
        return $this->relativeTimeLock;
81
    }
82
83
    /**
84
     * @return bool
85
     */
86
    public function isRelativeToBlock(): bool
87
    {
88
        if ($this->isDisabled()) {
89
            throw new \RuntimeException("This opcode seems to be disabled");
90
        }
91
92
        return ($this->relativeTimeLock & TransactionInput::SEQUENCE_LOCKTIME_TYPE_FLAG) === 0;
93
    }
94
95
    /**
96
     * @return bool
97
     */
98
    public function isDisabled(): bool
99
    {
100
        return ($this->relativeTimeLock & TransactionInput::SEQUENCE_LOCKTIME_DISABLE_FLAG) != 0;
101
    }
102
}
103