Completed
Pull Request — master (#240)
by thomas
73:04
created

Transaction::isCoinbase()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

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