Completed
Pull Request — master (#346)
by thomas
58:32 queued 55:13
created

Transaction::getSignatureHash()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 2
c 0
b 0
f 0
nc 1
nop 0
dl 0
loc 4
ccs 0
cts 2
cp 0
crap 2
rs 10
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\Utxo\Utxo;
15
use BitWasp\Buffertools\BufferInterface;
16
17
class Transaction extends Serializable implements TransactionInterface
18
{
19
    /**
20
     * @var int
21
     */
22
    private $version;
23
24
    /**
25
     * @var TransactionInputCollection
26
     */
27
    private $inputs;
28
29
    /**
30
     * @var TransactionOutputCollection
31
     */
32
    private $outputs;
33
34
    /**
35
     * @var TransactionWitnessCollection
36
     */
37
    private $witness;
38
39
    /**
40
     * @var int
41
     */
42
    private $lockTime;
43
44
    /**
45
     * Transaction constructor.
46
     *
47
     * @param int $nVersion
48
     * @param TransactionInputCollection|null $inputs
49
     * @param TransactionOutputCollection|null $outputs
50
     * @param TransactionWitnessCollection|null $witness
51
     * @param int $nLockTime
52
     */
53 2485
    public function __construct(
54
        $nVersion = TransactionInterface::DEFAULT_VERSION,
55
        TransactionInputCollection $inputs = null,
56
        TransactionOutputCollection $outputs = null,
57
        TransactionWitnessCollection $witness = null,
58
        $nLockTime = 0
59
    ) {
60 2485
        if ($nVersion > TransactionInterface::MAX_VERSION) {
61 3
            throw new \InvalidArgumentException('Version must be less than ' . TransactionInterface::MAX_VERSION);
62
        }
63
64 2482
        if ($nLockTime < 0 || $nLockTime > TransactionInterface::MAX_LOCKTIME) {
65 3
            throw new \InvalidArgumentException('Locktime must be positive and less than ' . TransactionInterface::MAX_LOCKTIME);
66
        }
67
68 2479
        $this->version = $nVersion;
69 2479
        $this->inputs = $inputs ?: new TransactionInputCollection();
70 2479
        $this->outputs = $outputs ?: new TransactionOutputCollection();
71 2479
        $this->witness = $witness ?: new TransactionWitnessCollection();
72 2479
        $this->lockTime = $nLockTime;
73
74 2479
    }
75
76
    /**
77
     * @return Transaction
78
     */
79 157
    public function __clone()
80
    {
81 157
        $this->inputs = clone $this->inputs;
82 157
        $this->outputs = clone $this->outputs;
83 157
    }
84
85
    /**
86
     * @return BufferInterface
87
     */
88 2254
    public function getTxHash()
89
    {
90 2254
        return Hash::sha256d($this->getBuffer());
91
    }
92
93
    /**
94
     * @return BufferInterface
95
     */
96 2254
    public function getTxId()
97
    {
98 2254
        return $this->getTxHash()->flip();
99
    }
100
101
    /**
102
     * @return BufferInterface
103
     */
104
    public function getWitnessTxId()
105
    {
106
        return Hash::sha256d($this->getWitnessBuffer())->flip();
107
    }
108
109
    /**
110
     * @return int
111
     */
112 2335
    public function getVersion()
113
    {
114 2335
        return $this->version;
115
    }
116
117
    /**
118
     * Get the array of inputs in the transaction
119
     *
120
     * @return TransactionInputCollection
121
     */
122 2335
    public function getInputs()
123
    {
124 2335
        return $this->inputs;
125
    }
126
127
    /**
128
     * @param int $index
129
     * @return TransactionInputInterface
130
     */
131 85
    public function getInput($index)
132
    {
133 85
        return $this->inputs[$index];
134
    }
135
136
    /**
137
     * Get Outputs
138
     *
139
     * @return TransactionOutputCollection
140
     */
141 2353
    public function getOutputs()
142
    {
143 2353
        return $this->outputs;
144
    }
145
146
    /**
147
     * @param int $vout
148
     * @return TransactionOutputInterface
149
     */
150 2245
    public function getOutput($vout)
151 18
    {
152 2245
        return $this->outputs[$vout];
153
    }
154
155
    /**
156
     * @return TransactionWitnessCollection
157
     */
158 148
    public function getWitnesses()
159
    {
160 148
        return $this->witness;
161
    }
162
163
    /**
164
     * @return ScriptWitnessInterface
165
     */
166
    public function getWitness($index)
167
    {
168
        return $this->witness[$index];
169
    }
170
171
    /**
172
     * @param int $vout
173
     * @return OutPointInterface
174
     */
175 2206
    public function makeOutpoint($vout)
176
    {
177 2206
        $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...
178 2206
        return new OutPoint($this->getTxId(), $vout);
179
    }
180
181
    /**
182
     * @param int $vout
183
     * @return Utxo
184
     */
185
    public function makeUtxo($vout)
186
    {
187
        return new Utxo(new OutPoint($this->getTxId(), $vout), $this->getOutput($vout));
188
    }
189
190
    /**
191
     * Get Lock Time
192
     *
193
     * @return int
194
     */
195 2338
    public function getLockTime()
196
    {
197 2338
        return $this->lockTime;
198
    }
199
200
    /**
201
     * @return int|string
202
     */
203 3
    public function getValueOut()
204
    {
205 3
        $math = Bitcoin::getMath();
206 3
        $value = gmp_init(0);
207 3
        foreach ($this->outputs as $output) {
208 3
            $value = $math->add($value, gmp_init($output->getValue()));
209 2
        }
210
211 3
        return gmp_strval($value, 10);
212
    }
213
214
    /**
215
     * @return bool
216
     */
217 3
    public function isCoinbase()
218
    {
219 3
        return count($this->inputs) === 1 && $this->getInput(0)->isCoinBase();
220
    }
221
222
    /**
223
     * @param TransactionInterface $tx
224
     * @return bool
225
     */
226 3
    public function equals(TransactionInterface $tx)
227
    {
228 3
        $version = gmp_cmp($this->version, $tx->getVersion());
229 3
        if ($version !== 0) {
230 3
            return false;
231
        }
232
233 3
        $nIn = count($this->inputs);
234 3
        $nOut = count($this->outputs);
235 3
        $nWit = count($this->witness);
236 3
        if ($nIn !== count($tx->getInputs()) || $nOut !== count($tx->getOutputs()) || $nWit !== count($tx->getWitnesses())) {
237 3
            return false;
238
        }
239
240 3
        for ($i = 0; $i < $nIn; $i++) {
241 3
            if (false === $this->getInput($i)->equals($tx->getInput($i))) {
242 3
                return false;
243
            }
244 2
        }
245
246 3
        for ($i = 0; $i < $nOut; $i++) {
247 3
            if (false === $this->getOutput($i)->equals($tx->getOutput($i))) {
248 3
                return false;
249
            }
250 2
        }
251
252 3
        for ($i = 0; $i < $nWit; $i++) {
253
            if (false === $this->getWitness($i)->equals($tx->getWitness($i))) {
254
                return false;
255
            }
256
        }
257
258 3
        return gmp_cmp($this->lockTime, $tx->getLockTime()) === 0;
259
    }
260
261
    /**
262
     * @return Validator
263
     */
264 27
    public function validator()
265
    {
266 27
        return new Validator($this);
267
    }
268
269
    /**
270
     * @return BufferInterface
271
     */
272 2299
    public function getBuffer()
273
    {
274 2299
        return (new OldTransactionSerializer())->serialize($this);
275
    }
276
277
    /**
278
     * @return BufferInterface
279
     */
280 27
    public function getWitnessBuffer()
281
    {
282 27
        return (new TransactionSerializer())->serialize($this);
283
    }
284
}
285