1 | <?php |
||||
2 | |||||
3 | declare(strict_types=1); |
||||
4 | |||||
5 | namespace BitWasp\Bitcoin\Transaction; |
||||
6 | |||||
7 | use BitWasp\Bitcoin\Bitcoin; |
||||
8 | use BitWasp\Bitcoin\Script\ScriptInterface; |
||||
9 | use BitWasp\Bitcoin\Serializable; |
||||
10 | use BitWasp\Bitcoin\Serializer\Transaction\OutPointSerializer; |
||||
11 | use BitWasp\Bitcoin\Serializer\Transaction\TransactionInputSerializer; |
||||
12 | use BitWasp\Buffertools\BufferInterface; |
||||
13 | |||||
14 | class TransactionInput extends Serializable implements TransactionInputInterface |
||||
15 | { |
||||
16 | /** |
||||
17 | * @var OutPointInterface |
||||
18 | */ |
||||
19 | private $outPoint; |
||||
20 | |||||
21 | /** |
||||
22 | * @var ScriptInterface |
||||
23 | */ |
||||
24 | private $script; |
||||
25 | |||||
26 | /** |
||||
27 | * @var int |
||||
28 | */ |
||||
29 | private $sequence; |
||||
30 | |||||
31 | /** |
||||
32 | * @param OutPointInterface $outPoint |
||||
33 | * @param ScriptInterface $script |
||||
34 | * @param int $sequence |
||||
35 | */ |
||||
36 | 5277 | public function __construct(OutPointInterface $outPoint, ScriptInterface $script, int $sequence = self::SEQUENCE_FINAL) |
|||
37 | { |
||||
38 | 5277 | $this->outPoint = $outPoint; |
|||
39 | 5277 | $this->script = $script; |
|||
40 | 5277 | $this->sequence = $sequence; |
|||
41 | 5277 | } |
|||
42 | |||||
43 | /** |
||||
44 | * @return OutPointInterface |
||||
45 | */ |
||||
46 | 5262 | public function getOutPoint(): OutPointInterface |
|||
47 | { |
||||
48 | 5262 | return $this->outPoint; |
|||
49 | } |
||||
50 | |||||
51 | /** |
||||
52 | * @return ScriptInterface |
||||
53 | */ |
||||
54 | 5292 | public function getScript(): ScriptInterface |
|||
55 | { |
||||
56 | 5292 | return $this->script; |
|||
57 | } |
||||
58 | |||||
59 | /** |
||||
60 | * @return int |
||||
61 | */ |
||||
62 | 5270 | public function getSequence(): int |
|||
63 | { |
||||
64 | 5270 | return $this->sequence; |
|||
65 | } |
||||
66 | |||||
67 | /** |
||||
68 | * @param TransactionInputInterface $other |
||||
69 | * @return bool |
||||
70 | */ |
||||
71 | 9 | public function equals(TransactionInputInterface $other): bool |
|||
72 | { |
||||
73 | 9 | if (!$this->outPoint->equals($other->getOutPoint())) { |
|||
74 | 2 | return false; |
|||
75 | } |
||||
76 | |||||
77 | 9 | if (!$this->script->equals($other->getScript())) { |
|||
78 | 1 | return false; |
|||
79 | } |
||||
80 | |||||
81 | 9 | return gmp_cmp(gmp_init($this->sequence), gmp_init($other->getSequence())) === 0; |
|||
82 | } |
||||
83 | |||||
84 | /** |
||||
85 | * Check whether this transaction is a Coinbase transaction |
||||
86 | * |
||||
87 | * @return bool |
||||
88 | */ |
||||
89 | 4 | public function isCoinbase(): bool |
|||
90 | { |
||||
91 | 4 | $outpoint = $this->outPoint; |
|||
92 | 4 | return $outpoint->getTxId()->getBinary() === str_pad('', 32, "\x00") |
|||
93 | 4 | && $outpoint->getVout() == 0xffffffff; |
|||
94 | } |
||||
95 | |||||
96 | /** |
||||
97 | * @return bool |
||||
98 | */ |
||||
99 | 12 | public function isFinal(): bool |
|||
100 | { |
||||
101 | 12 | $math = Bitcoin::getMath(); |
|||
102 | 12 | return $math->cmp(gmp_init($this->getSequence(), 10), gmp_init(self::SEQUENCE_FINAL, 10)) === 0; |
|||
0 ignored issues
–
show
Bug
introduced
by
![]() It seems like
gmp_init($this->getSequence(), 10) can also be of type resource ; however, parameter $first of Mdanter\Ecc\Math\GmpMath::cmp() does only seem to accept GMP , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
103 | } |
||||
104 | |||||
105 | /** |
||||
106 | * @return bool |
||||
107 | */ |
||||
108 | 2 | public function isSequenceLockDisabled(): bool |
|||
109 | { |
||||
110 | 2 | if ($this->isCoinbase()) { |
|||
111 | 1 | return true; |
|||
112 | } |
||||
113 | |||||
114 | 2 | return ($this->sequence & self::SEQUENCE_LOCKTIME_DISABLE_FLAG) !== 0; |
|||
115 | } |
||||
116 | |||||
117 | /** |
||||
118 | * @return bool |
||||
119 | */ |
||||
120 | 1 | public function isLockedToTime(): bool |
|||
121 | { |
||||
122 | 1 | return !$this->isSequenceLockDisabled() && (($this->sequence & self::SEQUENCE_LOCKTIME_TYPE_FLAG) === self::SEQUENCE_LOCKTIME_TYPE_FLAG); |
|||
123 | } |
||||
124 | |||||
125 | /** |
||||
126 | * @return bool |
||||
127 | */ |
||||
128 | 1 | public function isLockedToBlock(): bool |
|||
129 | { |
||||
130 | 1 | return !$this->isSequenceLockDisabled() && (($this->sequence & self::SEQUENCE_LOCKTIME_TYPE_FLAG) === 0); |
|||
131 | } |
||||
132 | |||||
133 | /** |
||||
134 | * @return int |
||||
135 | */ |
||||
136 | 1 | public function getRelativeTimeLock(): int |
|||
137 | { |
||||
138 | 1 | if (!$this->isLockedToTime()) { |
|||
139 | throw new \RuntimeException('Cannot decode time based locktime when disable flag set/timelock flag unset/tx is coinbase'); |
||||
140 | } |
||||
141 | |||||
142 | // Multiply by 512 to convert locktime to seconds |
||||
143 | 1 | return ($this->sequence & self::SEQUENCE_LOCKTIME_MASK) * 512; |
|||
144 | } |
||||
145 | |||||
146 | /** |
||||
147 | * @return int |
||||
148 | */ |
||||
149 | 1 | public function getRelativeBlockLock(): int |
|||
150 | { |
||||
151 | 1 | if (!$this->isLockedToBlock()) { |
|||
152 | throw new \RuntimeException('Cannot decode block locktime when disable flag set/timelock flag set/tx is coinbase'); |
||||
153 | } |
||||
154 | |||||
155 | 1 | return $this->sequence & self::SEQUENCE_LOCKTIME_MASK; |
|||
156 | } |
||||
157 | |||||
158 | /** |
||||
159 | * @return BufferInterface |
||||
160 | */ |
||||
161 | 1 | public function getBuffer(): BufferInterface |
|||
162 | { |
||||
163 | 1 | return (new TransactionInputSerializer(new OutPointSerializer()))->serialize($this); |
|||
164 | } |
||||
165 | } |
||||
166 |