Completed
Pull Request — master (#220)
by thomas
73:29 queued 68:53
created

Transaction::getBuffer()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
cc 1
eloc 2
nc 1
nop 0
crap 1
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 1216
    public function __construct(
48
        $nVersion = TransactionInterface::DEFAULT_VERSION,
49
        TransactionInputCollection $inputs = null,
50
        TransactionOutputCollection $outputs = null,
51
        $nLockTime = '0'
52
    ) {
53
54 1216
        if (!is_numeric($nVersion)) {
55 6
            throw new \InvalidArgumentException('Transaction version must be numeric');
56
        }
57
58 1210
        if (!is_numeric($nLockTime)) {
59 6
            throw new \InvalidArgumentException('Transaction locktime must be numeric');
60
        }
61
62 1204
        $math = Bitcoin::getMath();
63 1204
        if ($math->cmp($nVersion, TransactionInterface::MAX_VERSION) > 0) {
64 6
            throw new \InvalidArgumentException('Version must be less than ' . TransactionInterface::MAX_VERSION);
65
        }
66
67 1198
        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 1192
        $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 1192
        $this->inputs = $inputs ?: new TransactionInputCollection();
73 1192
        $this->outputs = $outputs ?: new TransactionOutputCollection();
74 1192
        $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 1192
        $this
77 1192
            ->initFunctionAlias('version', 'getVersion')
78 1192
            ->initFunctionAlias('inputs', 'getInputs')
79 1192
            ->initFunctionAlias('outputs', 'getOutputs')
80 1192
            ->initFunctionAlias('locktime', 'getLockTime');
81 1192
    }
82
83
    /**
84
     * @return Transaction
85
     */
86 110
    public function __clone()
87
    {
88 110
        $this->inputs = clone $this->inputs;
89 110
        $this->outputs = clone $this->outputs;
90 110
    }
91
92
    /**
93
     * @return Buffer
94
     */
95 182
    public function getTxHash()
96
    {
97 182
        return Hash::sha256d($this->getBuffer());
98
    }
99
100
    /**
101
     * @return Buffer
102
     */
103 182
    public function getTxId()
104
    {
105 182
        return $this->getTxHash()->flip();
106
    }
107
108
    /**
109
     * @return int|string
110
     */
111 320
    public function getVersion()
112
    {
113 320
        return $this->version;
114
    }
115
116
    /**
117
     * Get the array of inputs in the transaction
118
     *
119
     * @return TransactionInputCollection
120
     */
121 994
    public function getInputs()
122
    {
123 994
        return $this->inputs;
124
    }
125
126
    /**
127
     * @param int $index
128
     * @return TransactionInputInterface
129
     */
130 104
    public function getInput($index)
131
    {
132 104
        return $this->inputs[$index];
133
    }
134
135
    /**
136
     * Get Outputs
137
     *
138
     * @return TransactionOutputCollection
139
     */
140 328
    public function getOutputs()
141
    {
142 328
        return $this->outputs;
143
    }
144
145
    /**
146
     * @param int $vout
147
     * @return TransactionOutputInterface
148
     */
149 152
    public function getOutput($vout)
150
    {
151 152
        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 326
    public function getLockTime()
184
    {
185 326
        return $this->lockTime;
186
    }
187
188
    /**
189
     * @return \BitWasp\Bitcoin\Transaction\SignatureHash\SignatureHashInterface
190
     */
191 94
    public function getSignatureHash()
192
    {
193 94
        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 Buffer
220
     */
221 290
    public function getBuffer()
222
    {
223 290
        return (new TransactionSerializer)->serialize($this);
224
    }
225
}
226