Completed
Pull Request — master (#241)
by thomas
133:23 queued 63:06
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
rs 10
ccs 0
cts 0
cp 0
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\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\TransactionSerializer;
14
use BitWasp\Bitcoin\Serializer\Transaction\WitnessTransactionSerializer;
15
use BitWasp\Bitcoin\Transaction\SignatureHash\Hasher;
16
use BitWasp\Bitcoin\Utxo\Utxo;
17
use BitWasp\Buffertools\BufferInterface;
18
use BitWasp\CommonTrait\FunctionAliasArrayAccess;
19
20
class Transaction extends Serializable implements TransactionInterface
21
{
22
    use FunctionAliasArrayAccess;
23
24
    /**
25
     * @var int|string
26
     */
27
    private $version;
28
29
    /**
30
     * @var TransactionInputCollection
31
     */
32
    private $inputs;
33
34
    /**
35
     * @var TransactionOutputCollection
36
     */
37
    private $outputs;
38
39
    /**
40
     * @var TransactionWitnessCollection
41
     */
42
    private $witness;
43
44
    /**
45
     * @var int|string
46
     */
47 1220
    private $lockTime;
48
49
    /**
50
     * Transaction constructor.
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 int|string
122
     */
123 998
    public function getVersion()
124
    {
125
        return $this->version;
126
    }
127
128
    /**
129
     * Get the array of inputs in the transaction
130 106
     *
131
     * @return TransactionInputCollection
132 106
     */
133
    public function getInputs()
134
    {
135
        return $this->inputs;
136
    }
137
138
    /**
139
     * @param int $index
140 332
     * @return TransactionInputInterface
141
     */
142 332
    public function getInput($index)
143
    {
144
        return $this->inputs[$index];
145
    }
146
147
    /**
148
     * Get Outputs
149 154
     *
150
     * @return TransactionOutputCollection
151 154
     */
152
    public function getOutputs()
153
    {
154
        return $this->outputs;
155
    }
156
157
    /**
158 24
     * @param int $vout
159
     * @return TransactionOutputInterface
160 24
     */
161 24
    public function getOutput($vout)
162
    {
163
        return $this->outputs[$vout];
164
    }
165
166
    /**
167
     * @return TransactionWitnessCollection
168
     */
169
    public function getWitnesses()
170
    {
171
        return $this->witness;
172
    }
173
174
    /**
175
     * @return ScriptWitnessInterface
176
     */
177
    public function getWitness($index)
178
    {
179
        return $this->witness[$index];
180
    }
181
182
    /**
183 328
     * @param int $vout
184
     * @return OutPointInterface
185 328
     */
186
    public function makeOutpoint($vout)
187
    {
188
        $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...
189
        return new OutPoint($this->getTxId(), $vout);
190
    }
191 98
192
    /**
193 98
     * @param int $vout
194
     * @return Utxo
195
     */
196
    public function makeUtxo($vout)
197
    {
198
        $output = $this->getOutput($vout);
199 6
200
        return new Utxo(
201 6
            new OutPoint($this->getTxId(), $vout),
202 6
            $output
203 6
        );
204 6
    }
205 6
206
    /**
207 6
     * Get Lock Time
208
     *
209
     * @return int|string
210
     */
211
    public function getLockTime()
212
    {
213 6
        return $this->lockTime;
214
    }
215 6
216
    /**
217
     * @return \BitWasp\Bitcoin\Transaction\SignatureHash\SigHash
218
     */
219
    public function getSignatureHash()
220
    {
221
        return new Hasher($this);
222
    }
223
224
    /**
225
     * @return int|string
226
     */
227
    public function getValueOut()
228
    {
229 292
        $math = Bitcoin::getMath();
230
        $value = 0;
231 292
        foreach ($this->outputs as $output) {
232
            $value = $math->add($value, $output->getValue());
233
        }
234
235
        return $value;
236
    }
237
238
    /**
239
     * @return bool
240
     */
241
    public function isCoinbase()
242
    {
243
        return count($this->inputs) === 1 && $this->getInput(0)->isCoinBase();
244
    }
245
246
    /**
247
     * @return Validator
248
     */
249
    public function validator()
250
    {
251
        return new Validator($this);
252
    }
253
254
    /**
255
     * @return BufferInterface
256
     */
257
    public function getBuffer()
258
    {
259
        return (new TransactionSerializer)->serialize($this);
260
    }
261
262
    /**
263
     * @return string
264
     */
265
    public function getWitnessBuffer()
266
    {
267
        return (new NTransactionSerializer())->serialize($this);
268
    }
269
}
270