Completed
Push — master ( cfc147...a22632 )
by thomas
211:07 queued 207:46
created

Transaction::getValueOut()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 6
nc 2
nop 0
dl 0
loc 10
ccs 7
cts 7
cp 1
crap 2
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 5000
    public function __construct(
51
        $nVersion = TransactionInterface::DEFAULT_VERSION,
52
        array $vin = [],
53
        array $vout = [],
54
        array $vwit = [],
55
        $nLockTime = 0
56
    ) {
57 5000
        if ($nVersion > TransactionInterface::MAX_VERSION) {
58 6
            throw new \InvalidArgumentException('Version must be less than ' . TransactionInterface::MAX_VERSION);
59
        }
60
61 4994
        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 4988
        $this->version = $nVersion;
66 4988
        $this->lockTime = $nLockTime;
67
68
        $this->inputs = array_map(function (TransactionInputInterface $input) {
69 4784
            return $input;
70 4988
        }, $vin);
71
        $this->outputs = array_map(function (TransactionOutputInterface $output) {
72 4808
            return $output;
73 4988
        }, $vout);
74 4988
        $this->witness = array_map(function (ScriptWitnessInterface $scriptWitness) {
75 4472
            return $scriptWitness;
76 4988
        }, $vwit);
77 4988
    }
78
79
    /**
80
     * @return Transaction
81
     */
82 308
    public function __clone()
83
    {
84
        //$this->inputs = clone $this->inputs;
85
        //$this->outputs = clone $this->outputs;
86 308
    }
87
88
    /**
89
     * @return BufferInterface
90
     */
91 4508
    public function getTxHash()
92
    {
93 4508
        return Hash::sha256d($this->getBuffer());
94
    }
95
96
    /**
97
     * @return BufferInterface
98
     */
99 4508
    public function getTxId()
100
    {
101 4508
        return $this->getTxHash()->flip();
102
    }
103
104
    /**
105
     * @return BufferInterface
106
     */
107
    public function getWitnessTxId()
108
    {
109
        return Hash::sha256d($this->getWitnessBuffer())->flip();
110
    }
111
112
    /**
113
     * @return int
114
     */
115 4718
    public function getVersion()
116
    {
117 4718
        return $this->version;
118
    }
119
120
    /**
121
     * Get the array of inputs in the transaction
122
     *
123
     * @return TransactionInputInterface[]
124
     */
125 4700
    public function getInputs()
126
    {
127 4700
        return $this->inputs;
128
    }
129
130
    /**
131
     * @param int $index
132
     * @return TransactionInputInterface
133
     */
134 218
    public function getInput($index)
135
    {
136 218
        if (!isset($this->inputs[$index])) {
137 6
            throw new \RuntimeException('No input at this index');
138
        }
139 212
        return $this->inputs[$index];
140
    }
141
142
    /**
143
     * Get Outputs
144
     *
145
     * @return TransactionOutputInterface[]
146
     */
147 4742
    public function getOutputs()
148
    {
149 4742
        return $this->outputs;
150
    }
151
152
    /**
153
     * @param int $vout
154
     * @return TransactionOutputInterface
155
     */
156 4502
    public function getOutput($vout)
157
    {
158 4502
        if (!isset($this->outputs[$vout])) {
159 6
            throw new \RuntimeException('No output at this index');
160
        }
161 4496
        return $this->outputs[$vout];
162
    }
163
164
    /**
165
     * @return bool
166
     */
167
    public function hasWitness()
168
    {
169
        for ($l = count($this->inputs), $i = 0; $i < $l; $i++) {
170
            if (isset($this->witness[$i]) && count($this->witness[$i]) > 0) {
171
                return true;
172
            }
173
        }
174
175
        return false;
176
    }
177
178
    /**
179
     * @return ScriptWitnessInterface[]
180
     */
181 296
    public function getWitnesses()
182
    {
183 296
        return $this->witness;
184
    }
185
186
    /**
187
     * @return ScriptWitnessInterface
188
     */
189
    public function getWitness($index)
190
    {
191
        if (!isset($this->witness[$index])) {
192
            throw new \RuntimeException('No witness at this index');
193
        }
194
        return $this->witness[$index];
195
    }
196
197
    /**
198
     * @param int $vout
199
     * @return OutPointInterface
200
     */
201 4412
    public function makeOutpoint($vout)
202
    {
203 4412
        $this->getOutput($vout);
204 4412
        return new OutPoint($this->getTxId(), $vout);
205
    }
206
207
    /**
208
     * @param int $vout
209
     * @return Utxo
210
     */
211
    public function makeUtxo($vout)
212
    {
213
        return new Utxo(new OutPoint($this->getTxId(), $vout), $this->getOutput($vout));
214
    }
215
216
    /**
217
     * Get Lock Time
218
     *
219
     * @return int
220
     */
221 4724
    public function getLockTime()
222
    {
223 4724
        return $this->lockTime;
224
    }
225
226
    /**
227
     * @return int|string
228
     */
229 6
    public function getValueOut()
230
    {
231 6
        $math = Bitcoin::getMath();
232 6
        $value = gmp_init(0);
233 6
        foreach ($this->outputs as $output) {
234 6
            $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 234 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...
235 2
        }
236
237 6
        return gmp_strval($value, 10);
238
    }
239
240
    /**
241
     * @return bool
242
     */
243 6
    public function isCoinbase()
244
    {
245 6
        return count($this->inputs) === 1 && $this->getInput(0)->isCoinBase();
246
    }
247
248
    /**
249
     * @param TransactionInterface $tx
250
     * @return bool
251
     */
252 6
    public function equals(TransactionInterface $tx)
253
    {
254 6
        $version = gmp_cmp($this->version, $tx->getVersion());
255 6
        if ($version !== 0) {
256 6
            return false;
257
        }
258
259 6
        $nIn = count($this->inputs);
260 6
        $nOut = count($this->outputs);
261 6
        $nWit = count($this->witness);
262 6
        if ($nIn !== count($tx->getInputs()) || $nOut !== count($tx->getOutputs()) || $nWit !== count($tx->getWitnesses())) {
263 6
            return false;
264
        }
265
266 6
        for ($i = 0; $i < $nIn; $i++) {
267 6
            if (false === $this->getInput($i)->equals($tx->getInput($i))) {
268 6
                return false;
269
            }
270 2
        }
271
272 6
        for ($i = 0; $i < $nOut; $i++) {
273 6
            if (false === $this->getOutput($i)->equals($tx->getOutput($i))) {
274 6
                return false;
275
            }
276 2
        }
277
278 6
        for ($i = 0; $i < $nWit; $i++) {
279
            if (false === $this->getWitness($i)->equals($tx->getWitness($i))) {
280
                return false;
281
            }
282
        }
283
284 6
        return gmp_cmp($this->lockTime, $tx->getLockTime()) === 0;
285
    }
286
287
    /**
288
     * @return Validator
289
     */
290 54
    public function validator()
291
    {
292 54
        return new Validator($this);
293
    }
294
295
    /**
296
     * @return BufferInterface
297
     */
298 4613
    public function getBuffer()
299
    {
300 4613
        return (new OldTransactionSerializer())->serialize($this);
301
    }
302
303
    /**
304
     * @return BufferInterface
305
     */
306 54
    public function getWitnessBuffer()
307
    {
308 54
        return (new TransactionSerializer())->serialize($this);
309
    }
310
}
311