Completed
Push — master ( 4ca74a...73e746 )
by thomas
14s
created

Transaction::__clone()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 5
ccs 2
cts 2
cp 1
crap 1
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
namespace BitWasp\Bitcoin\Transaction;
4
5
use BitWasp\Bitcoin\Bitcoin;
6
use BitWasp\Bitcoin\Crypto\Hash;
7
use BitWasp\Bitcoin\Script\ScriptWitnessInterface;
8
use BitWasp\Bitcoin\Serializable;
9
use BitWasp\Bitcoin\Serializer\Transaction\OldTransactionSerializer;
10
use BitWasp\Bitcoin\Serializer\Transaction\TransactionSerializer;
11
use BitWasp\Bitcoin\Utxo\Utxo;
12
use BitWasp\Buffertools\BufferInterface;
13
14
class Transaction extends Serializable implements TransactionInterface
15
{
16
    /**
17
     * @var int
18
     */
19
    private $version;
20
21
    /**
22
     * @var TransactionInputInterface[]
23
     */
24
    private $inputs;
25
26
    /**
27
     * @var TransactionOutputInterface[]
28
     */
29
    private $outputs;
30
31
    /**
32
     * @var ScriptWitnessInterface[]
33
     */
34
    private $witness;
35
36
    /**
37
     * @var int
38
     */
39
    private $lockTime;
40
41
    /**
42
     * Transaction constructor.
43
     *
44
     * @param int $nVersion
45
     * @param TransactionInputInterface[] $vin
46
     * @param TransactionOutputInterface[] $vout
47
     * @param ScriptWitnessInterface[] $vwit
48
     * @param int $nLockTime
49
     */
50 2914
    public function __construct(
51
        $nVersion = TransactionInterface::DEFAULT_VERSION,
52
        array $vin = [],
53
        array $vout = [],
54
        array $vwit = [],
55
        $nLockTime = 0
56
    ) {
57 2914
        if ($nVersion > TransactionInterface::MAX_VERSION) {
58 6
            throw new \InvalidArgumentException('Version must be less than ' . TransactionInterface::MAX_VERSION);
59
        }
60
61 2908
        if ($nLockTime < 0 || $nLockTime > TransactionInterface::MAX_LOCKTIME) {
62 6
            throw new \InvalidArgumentException('Locktime must be positive and less than ' . TransactionInterface::MAX_LOCKTIME);
63
        }
64
65 2902
        $this->version = $nVersion;
66 2902
        $this->lockTime = $nLockTime;
67
68
        $this->inputs = array_map(function (TransactionInputInterface $input) {
69 2698
            return $input;
70 2902
        }, $vin);
71
        $this->outputs = array_map(function (TransactionOutputInterface $output) {
72 2710
            return $output;
73 2902
        }, $vout);
74 2902
        $this->witness = array_map(function (ScriptWitnessInterface $scriptWitness) {
75 2452
            return $scriptWitness;
76 2902
        }, $vwit);
77 2902
    }
78
79
    /**
80
     * @return BufferInterface
81
     */
82 304
    public function getTxHash()
83
    {
84
        return Hash::sha256d($this->getBuffer());
85
    }
86 304
87
    /**
88
     * @return BufferInterface
89
     */
90
    public function getTxId()
91 2380
    {
92
        return $this->getTxHash()->flip();
93 2380
    }
94
95
    /**
96
     * @return BufferInterface
97
     */
98
    public function getWitnessTxId()
99 2380
    {
100
        return Hash::sha256d($this->getWitnessBuffer())->flip();
101 2380
    }
102
103
    /**
104
     * @return int
105
     */
106
    public function getVersion()
107
    {
108
        return $this->version;
109
    }
110
111
    /**
112
     * Get the array of inputs in the transaction
113
     *
114
     * @return TransactionInputInterface[]
115 2644
     */
116
    public function getInputs()
117 2644
    {
118
        return $this->inputs;
119
    }
120
121
    /**
122
     * @param int $index
123
     * @return TransactionInputInterface
124
     */
125 2698
    public function getInput($index)
126
    {
127 2698
        if (!isset($this->inputs[$index])) {
128
            throw new \RuntimeException('No input at this index');
129
        }
130
        return $this->inputs[$index];
131
    }
132
133
    /**
134 262
     * Get Outputs
135
     *
136 262
     * @return TransactionOutputInterface[]
137 6
     */
138
    public function getOutputs()
139 256
    {
140
        return $this->outputs;
141
    }
142
143
    /**
144
     * @param int $vout
145
     * @return TransactionOutputInterface
146
     */
147 2674
    public function getOutput($vout)
148
    {
149 2674
        if (!isset($this->outputs[$vout])) {
150
            throw new \RuntimeException('No output at this index');
151
        }
152
        return $this->outputs[$vout];
153
    }
154
155
    /**
156 2368
     * @return bool
157
     */
158 2368
    public function hasWitness()
159 6
    {
160
        for ($l = count($this->inputs), $i = 0; $i < $l; $i++) {
161 2362
            if (isset($this->witness[$i]) && count($this->witness[$i]) > 0) {
162
                return true;
163
            }
164
        }
165
166
        return false;
167
    }
168
169
    /**
170
     * @return ScriptWitnessInterface[]
171
     */
172
    public function getWitnesses()
173
    {
174
        return $this->witness;
175
    }
176
177
    /**
178
     * @param int $index
179
     * @return ScriptWitnessInterface
180
     */
181 322
    public function getWitness($index)
182
    {
183 322
        if (!isset($this->witness[$index])) {
184
            throw new \RuntimeException('No witness at this index');
185
        }
186
        return $this->witness[$index];
187
    }
188
189
    /**
190 50
     * @param int $vout
191
     * @return OutPointInterface
192 50
     */
193
    public function makeOutpoint($vout)
194
    {
195 50
        $this->getOutput($vout);
196
        return new OutPoint($this->getTxId(), $vout);
197
    }
198
199
    /**
200
     * @param int $vout
201
     * @return Utxo
202 2296
     */
203
    public function makeUtxo($vout)
204 2296
    {
205 2296
        return new Utxo(new OutPoint($this->getTxId(), $vout), $this->getOutput($vout));
206
    }
207
208
    /**
209
     * Get Lock Time
210
     *
211
     * @return int
212
     */
213
    public function getLockTime()
214
    {
215
        return $this->lockTime;
216
    }
217
218
    /**
219
     * @return int|string
220
     */
221
    public function getValueOut()
222 2650
    {
223
        $math = Bitcoin::getMath();
224 2650
        $value = gmp_init(0);
225
        foreach ($this->outputs as $output) {
226
            $value = $math->add($value, gmp_init($output->getValue()));
0 ignored issues
show
Bug introduced by
It seems like $value defined by $math->add($value, gmp_init($output->getValue())) on line 226 can also be of type resource; however, Mdanter\Ecc\Math\GmpMath::add() does only seem to accept object<GMP>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
227
        }
228
229
        return gmp_strval($value, 10);
230 6
    }
231
232 6
    /**
233 6
     * @return bool
234 6
     */
235 6
    public function isCoinbase()
236 3
    {
237
        return count($this->inputs) === 1 && $this->getInput(0)->isCoinBase();
238 6
    }
239
240
    /**
241
     * @param TransactionInterface $tx
242
     * @return bool
243
     */
244 6
    public function equals(TransactionInterface $tx)
245
    {
246 6
        $version = gmp_cmp($this->version, $tx->getVersion());
247
        if ($version !== 0) {
248
            return false;
249
        }
250
251
        $nIn = count($this->inputs);
252
        $nOut = count($this->outputs);
253 6
        $nWit = count($this->witness);
254
255 6
        // Check the length of each field is equal
256 6
        if ($nIn !== count($tx->getInputs()) || $nOut !== count($tx->getOutputs()) || $nWit !== count($tx->getWitnesses())) {
257 6
            return false;
258
        }
259
260 6
        // Check each field
261 6
        for ($i = 0; $i < $nIn; $i++) {
262 6
            if (false === $this->getInput($i)->equals($tx->getInput($i))) {
263
                return false;
264
            }
265 6
        }
266 6
267
        for ($i = 0; $i < $nOut; $i++) {
268
            if (false === $this->getOutput($i)->equals($tx->getOutput($i))) {
269
                return false;
270 6
            }
271 6
        }
272 6
273
        for ($i = 0; $i < $nWit; $i++) {
274 3
            if (false === $this->getWitness($i)->equals($tx->getWitness($i))) {
275
                return false;
276 6
            }
277 6
        }
278 6
279
        return gmp_cmp($this->lockTime, $tx->getLockTime()) === 0;
280 3
    }
281
282 6
    /**
283
     * @return BufferInterface
284
     */
285
    public function getBuffer()
286
    {
287
        return (new OldTransactionSerializer())->serialize($this);
288 6
    }
289
290
    /**
291
     * @return BufferInterface
292
     */
293
    public function getWitnessBuffer()
294 2590
    {
295
        return (new TransactionSerializer())->serialize($this);
296 2590
    }
297
}
298