Completed
Push — master ( 55cd4a...70da09 )
by thomas
26:52
created

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