Completed
Push — master ( e7abd4...246998 )
by thomas
18:25
created

Transaction::equals()   C

Complexity

Conditions 11
Paths 17

Size

Total Lines 34
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 19
CRAP Score 11.307

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 34
ccs 19
cts 22
cp 0.8636
rs 5.2653
cc 11
eloc 19
nc 17
nop 1
crap 11.307

How to fix   Complexity   

Long Method

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

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

Commonly applied refactorings include:

1
<?php
2
3
namespace BitWasp\Bitcoin\Transaction;
4
5
use BitWasp\Bitcoin\Bitcoin;
6
use BitWasp\Bitcoin\Collection\Transaction\TransactionInputCollection;
7
use BitWasp\Bitcoin\Collection\Transaction\TransactionOutputCollection;
8
use BitWasp\Bitcoin\Collection\Transaction\TransactionWitnessCollection;
9
use BitWasp\Bitcoin\Crypto\Hash;
10
use BitWasp\Bitcoin\Script\ScriptWitnessInterface;
11
use BitWasp\Bitcoin\Serializable;
12
use BitWasp\Bitcoin\Serializer\Transaction\OldTransactionSerializer;
13
use BitWasp\Bitcoin\Serializer\Transaction\TransactionSerializer;
14
use BitWasp\Bitcoin\Transaction\SignatureHash\Hasher;
15
use BitWasp\Bitcoin\Utxo\Utxo;
16
use BitWasp\Buffertools\BufferInterface;
17
use BitWasp\CommonTrait\FunctionAliasArrayAccess;
18
19
class Transaction extends Serializable implements TransactionInterface
20
{
21
    use FunctionAliasArrayAccess;
22
23
    /**
24
     * @var int
25
     */
26
    private $version;
27
28
    /**
29
     * @var TransactionInputCollection
30
     */
31
    private $inputs;
32
33
    /**
34
     * @var TransactionOutputCollection
35
     */
36
    private $outputs;
37
38
    /**
39
     * @var TransactionWitnessCollection
40
     */
41
    private $witness;
42
43
    /**
44
     * @var int
45
     */
46
    private $lockTime;
47
48
    /**
49
     * Transaction constructor.
50
     *
51
     * @param int $nVersion
52
     * @param TransactionInputCollection|null $inputs
53
     * @param TransactionOutputCollection|null $outputs
54
     * @param TransactionWitnessCollection|null $witness
55
     * @param int $nLockTime
56
     */
57 636
    public function __construct(
58
        $nVersion = TransactionInterface::DEFAULT_VERSION,
59
        TransactionInputCollection $inputs = null,
60
        TransactionOutputCollection $outputs = null,
61
        TransactionWitnessCollection $witness = null,
62
        $nLockTime = 0
63
    ) {
64 636
        if ($nVersion > TransactionInterface::MAX_VERSION) {
65 3
            throw new \InvalidArgumentException('Version must be less than ' . TransactionInterface::MAX_VERSION);
66
        }
67
68 633
        if ($nLockTime < 0 || $nLockTime > TransactionInterface::MAX_LOCKTIME) {
69 3
            throw new \InvalidArgumentException('Locktime must be positive and less than ' . TransactionInterface::MAX_LOCKTIME);
70
        }
71
72 630
        $this->version = $nVersion;
73 630
        $this->inputs = $inputs ?: new TransactionInputCollection();
74 630
        $this->outputs = $outputs ?: new TransactionOutputCollection();
75 630
        $this->witness = $witness ?: new TransactionWitnessCollection();
76 630
        $this->lockTime = $nLockTime;
77
78 420
        $this
79 630
            ->initFunctionAlias('version', 'getVersion')
80 630
            ->initFunctionAlias('inputs', 'getInputs')
81 630
            ->initFunctionAlias('outputs', 'getOutputs')
82 630
            ->initFunctionAlias('locktime', 'getLockTime');
83 630
    }
84
85
    /**
86
     * @return Transaction
87
     */
88 63
    public function __clone()
89
    {
90 63
        $this->inputs = clone $this->inputs;
91 63
        $this->outputs = clone $this->outputs;
92 63
    }
93
94
    /**
95
     * @return BufferInterface
96
     */
97 60
    public function getTxHash()
98
    {
99 60
        return Hash::sha256d($this->getBuffer());
100
    }
101
102
    /**
103
     * @return BufferInterface
104
     */
105 60
    public function getTxId()
106
    {
107 60
        return $this->getTxHash()->flip();
108
    }
109
110
    /**
111
     * @return BufferInterface
112
     */
113
    public function getWitnessTxId()
114
    {
115
        return Hash::sha256d($this->getWitnessBuffer())->flip();
116
    }
117
118
    /**
119
     * @return int
120
     */
121 141
    public function getVersion()
122
    {
123 141
        return $this->version;
124
    }
125
126
    /**
127
     * Get the array of inputs in the transaction
128
     *
129
     * @return TransactionInputCollection
130
     */
131 486
    public function getInputs()
132
    {
133 486
        return $this->inputs;
134
    }
135
136
    /**
137
     * @param int $index
138
     * @return TransactionInputInterface
139
     */
140 57
    public function getInput($index)
141
    {
142 57
        return $this->inputs[$index];
143
    }
144
145
    /**
146
     * Get Outputs
147
     *
148
     * @return TransactionOutputCollection
149
     */
150 159
    public function getOutputs()
151 18
    {
152 159
        return $this->outputs;
153
    }
154
155
    /**
156
     * @param int $vout
157
     * @return TransactionOutputInterface
158
     */
159 51
    public function getOutput($vout)
160
    {
161 51
        return $this->outputs[$vout];
162
    }
163
164
    /**
165
     * @return TransactionWitnessCollection
166
     */
167 54
    public function getWitnesses()
168
    {
169 54
        return $this->witness;
170
    }
171
172
    /**
173
     * @return ScriptWitnessInterface
174
     */
175
    public function getWitness($index)
176
    {
177
        return $this->witness[$index];
178
    }
179
180
    /**
181
     * @param int $vout
182
     * @return OutPointInterface
183
     */
184 12
    public function makeOutpoint($vout)
185
    {
186 12
        $this->getOutput($vout);
0 ignored issues
show
Unused Code introduced by
The call to the method BitWasp\Bitcoin\Transact...ransaction::getOutput() seems un-needed as the method has no side-effects.

PHP Analyzer performs a side-effects analysis of your code. A side-effect is basically anything that might be visible after the scope of the method is left.

Let’s take a look at an example:

class User
{
    private $email;

    public function getEmail()
    {
        return $this->email;
    }

    public function setEmail($email)
    {
        $this->email = $email;
    }
}

If we look at the getEmail() method, we can see that it has no side-effect. Whether you call this method or not, no future calls to other methods are affected by this. As such code as the following is useless:

$user = new User();
$user->getEmail(); // This line could safely be removed as it has no effect.

On the hand, if we look at the setEmail(), this method _has_ side-effects. In the following case, we could not remove the method call:

$user = new User();
$user->setEmail('email@domain'); // This line has a side-effect (it changes an
                                 // instance variable).
Loading history...
187 12
        return new OutPoint($this->getTxId(), $vout);
188
    }
189
190
    /**
191
     * @param int $vout
192
     * @return Utxo
193
     */
194
    public function makeUtxo($vout)
195
    {
196
        return new Utxo(new OutPoint($this->getTxId(), $vout), $this->getOutput($vout));
197
    }
198
199
    /**
200
     * Get Lock Time
201
     *
202
     * @return int
203
     */
204 144
    public function getLockTime()
205
    {
206 144
        return $this->lockTime;
207
    }
208
209
    /**
210
     * @return Hasher
211
     */
212
    public function getSignatureHash()
213
    {
214
        return new Hasher($this);
215
    }
216
217
    /**
218
     * @return int|string
219
     */
220 3
    public function getValueOut()
221
    {
222 3
        $math = Bitcoin::getMath();
223 3
        $value = gmp_init(0);
224 3
        foreach ($this->outputs as $output) {
225 3
            $value = $math->add($value, gmp_init($output->getValue()));
226 2
        }
227
228 3
        return gmp_strval($value, 10);
229
    }
230
231
    /**
232
     * @return bool
233
     */
234 3
    public function isCoinbase()
235
    {
236 3
        return count($this->inputs) === 1 && $this->getInput(0)->isCoinBase();
237
    }
238
239
    /**
240
     * @param TransactionInterface $tx
241
     * @return bool
242
     */
243 3
    public function equals(TransactionInterface $tx)
244
    {
245 3
        $version = gmp_cmp($this->version, $tx->getVersion());
246 3
        if ($version !== 0) {
247 3
            return false;
248
        }
249
250 3
        $nIn = count($this->inputs);
251 3
        $nOut = count($this->outputs);
252 3
        $nWit = count($this->witness);
253 3
        if ($nIn !== count($tx->getInputs()) || $nOut !== count($tx->getOutputs()) || $nWit !== count($tx->getWitnesses())) {
254 3
            return false;
255
        }
256
257 3
        for ($i = 0; $i < $nIn; $i++) {
258 3
            if (false === $this->getInput($i)->equals($tx->getInput($i))) {
259 3
                return false;
260
            }
261 2
        }
262
263 3
        for ($i = 0; $i < $nOut; $i++) {
264 3
            if (false === $this->getOutput($i)->equals($tx->getOutput($i))) {
265 3
                return false;
266
            }
267 2
        }
268
269 3
        for ($i = 0; $i < $nWit; $i++) {
270
            if (false === $this->getWitness($i)->equals($tx->getWitness($i))) {
271
                return false;
272
            }
273
        }
274
275 3
        return gmp_cmp($this->lockTime, $tx->getLockTime()) === 0;
276
    }
277
278
    /**
279
     * @return Validator
280
     */
281 27
    public function validator()
282
    {
283 27
        return new Validator($this);
284
    }
285
286
    /**
287
     * @return BufferInterface
288
     */
289 105
    public function getBuffer()
290
    {
291 105
        return (new OldTransactionSerializer())->serialize($this);
292
    }
293
294
    /**
295
     * @return BufferInterface
296
     */
297 27
    public function getWitnessBuffer()
298
    {
299 27
        return (new TransactionSerializer())->serialize($this);
300
    }
301
}
302