Completed
Pull Request — master (#239)
by thomas
49:01 queued 45:29
created

Transaction::__construct()   D

Complexity

Conditions 9
Paths 12

Size

Total Lines 37
Code Lines 25

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 21
CRAP Score 9

Importance

Changes 2
Bugs 0 Features 1
Metric Value
c 2
b 0
f 1
dl 0
loc 37
ccs 21
cts 21
cp 1
rs 4.909
cc 9
eloc 25
nc 12
nop 5
crap 9
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|string
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|string
45
     */
46
    private $lockTime;
47 1220
48
    /**
49
     * Transaction constructor.
50
     *
51
     * @param int $nVersion
52
     * @param TransactionInputCollection|null $inputs
53
     * @param TransactionOutputCollection|null $outputs
54 1220
     * @param TransactionWitnessCollection|null $witness
55 6
     * @param int $nLockTime
56
     */
57
    public function __construct(
58 1214
        $nVersion = TransactionInterface::DEFAULT_VERSION,
59 6
        TransactionInputCollection $inputs = null,
60
        TransactionOutputCollection $outputs = null,
61
        TransactionWitnessCollection $witness = null,
62 1208
        $nLockTime = 0
63 1208
    ) {
64 6
65
        if (!is_numeric($nVersion)) {
66
            throw new \InvalidArgumentException('Transaction version must be numeric');
67 1202
        }
68 6
69
        if (!is_numeric($nLockTime)) {
70
            throw new \InvalidArgumentException('Transaction locktime must be numeric');
71 1196
        }
72 1196
73 1196
        $math = Bitcoin::getMath();
74 1196
        if ($math->cmp($nVersion, TransactionInterface::MAX_VERSION) > 0) {
75
            throw new \InvalidArgumentException('Version must be less than ' . TransactionInterface::MAX_VERSION);
76 1196
        }
77 1196
78 1196
        if ($math->cmp($nLockTime, 0) < 0 || $math->cmp($nLockTime, TransactionInterface::MAX_LOCKTIME) > 0) {
79 1196
            throw new \InvalidArgumentException('Locktime must be positive and less than ' . TransactionInterface::MAX_LOCKTIME);
80 1196
        }
81 1196
82
        $this->version = $nVersion;
0 ignored issues
show
Documentation Bug introduced by
It seems like $nVersion can also be of type double. However, the property $version is declared as type integer|string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
83
        $this->inputs = $inputs ?: new TransactionInputCollection();
84
        $this->outputs = $outputs ?: new TransactionOutputCollection();
85
        $this->witness = $witness ?: new TransactionWitnessCollection();
86 112
        $this->lockTime = $nLockTime;
0 ignored issues
show
Documentation Bug introduced by
It seems like $nLockTime can also be of type double. However, the property $lockTime is declared as type integer|string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
87
88 112
        $this
89 112
            ->initFunctionAlias('version', 'getVersion')
90 112
            ->initFunctionAlias('inputs', 'getInputs')
91
            ->initFunctionAlias('outputs', 'getOutputs')
92
            ->initFunctionAlias('locktime', 'getLockTime');
93
    }
94
95 184
    /**
96
     * @return Transaction
97 184
     */
98
    public function __clone()
99
    {
100
        $this->inputs = clone $this->inputs;
101
        $this->outputs = clone $this->outputs;
102
    }
103 184
104
    /**
105 184
     * @return BufferInterface
106
     */
107
    public function getTxHash()
108
    {
109
        return Hash::sha256d($this->getBuffer());
110
    }
111 322
112
    /**
113 322
     * @return BufferInterface
114
     */
115
    public function getTxId()
116
    {
117
        return $this->getTxHash()->flip();
118
    }
119
120
    /**
121 998
     * @return \BitWasp\Buffertools\BufferInterface
122
     */
123 998
    public function getWitnessTxId()
124
    {
125
        return Hash::sha256d($this->getWitnessBuffer())->flip();
126
    }
127
128
    /**
129
     * @return int|string
130 106
     */
131
    public function getVersion()
132 106
    {
133
        return $this->version;
134
    }
135
136
    /**
137
     * Get the array of inputs in the transaction
138
     *
139
     * @return TransactionInputCollection
140 332
     */
141
    public function getInputs()
142 332
    {
143
        return $this->inputs;
144
    }
145
146
    /**
147
     * @param int $index
148
     * @return TransactionInputInterface
149 154
     */
150
    public function getInput($index)
151 154
    {
152
        return $this->inputs[$index];
153
    }
154
155
    /**
156
     * Get Outputs
157
     *
158 24
     * @return TransactionOutputCollection
159
     */
160 24
    public function getOutputs()
161 24
    {
162
        return $this->outputs;
163
    }
164
165
    /**
166
     * @param int $vout
167
     * @return TransactionOutputInterface
168
     */
169
    public function getOutput($vout)
170
    {
171
        return $this->outputs[$vout];
172
    }
173
174
    /**
175
     * @return TransactionWitnessCollection
176
     */
177
    public function getWitnesses()
178
    {
179
        return $this->witness;
180
    }
181
182
    /**
183 328
     * @return ScriptWitnessInterface
184
     */
185 328
    public function getWitness($index)
186
    {
187
        return $this->witness[$index];
188
    }
189
190
    /**
191 98
     * @param int $vout
192
     * @return OutPointInterface
193 98
     */
194
    public function makeOutpoint($vout)
195
    {
196
        $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...
197
        return new OutPoint($this->getTxId(), $vout);
198
    }
199 6
200
    /**
201 6
     * @param int $vout
202 6
     * @return Utxo
203 6
     */
204 6
    public function makeUtxo($vout)
205 6
    {
206
        $output = $this->getOutput($vout);
207 6
208
        return new Utxo(
209
            new OutPoint($this->getTxId(), $vout),
210
            $output
211
        );
212
    }
213 6
214
    /**
215 6
     * Get Lock Time
216
     *
217
     * @return int|string
218
     */
219
    public function getLockTime()
220
    {
221
        return $this->lockTime;
222
    }
223
224
    /**
225
     * @return \BitWasp\Bitcoin\Transaction\SignatureHash\SigHash
226
     */
227
    public function getSignatureHash()
228
    {
229 292
        return new Hasher($this);
230
    }
231 292
232
    /**
233
     * @return int|string
234
     */
235
    public function getValueOut()
236
    {
237
        $math = Bitcoin::getMath();
238
        $value = 0;
239
        foreach ($this->outputs as $output) {
240
            $value = $math->add($value, $output->getValue());
241
        }
242
243
        return $value;
244
    }
245
246
    /**
247
     * @return bool
248
     */
249
    public function isCoinbase()
250
    {
251
        return count($this->inputs) === 1 && $this->getInput(0)->isCoinBase();
252
    }
253
254
    /**
255
     * @return Validator
256
     */
257
    public function validator()
258
    {
259
        return new Validator($this);
260
    }
261
262
    /**
263
     * @return BufferInterface
264
     */
265
    public function getBuffer()
266
    {
267
        return (new OldTransactionSerializer())->serialize($this);
268
    }
269
270
    /**
271
     * @return BufferInterface
272
     */
273
    public function getWitnessBuffer()
274
    {
275
        return (new TransactionSerializer())->serialize($this);
276
    }
277
}
278