Completed
Pull Request — master (#348)
by thomas
72:50 queued 67:29
created

TxBuilder   A

Complexity

Total Complexity 21

Size/Duplication

Total Lines 260
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 11

Test Coverage

Coverage 77.22%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
dl 0
loc 260
ccs 61
cts 79
cp 0.7722
rs 10
c 2
b 0
f 0
wmc 21
lcom 1
cbo 11

18 Methods

Rating   Name   Duplication   Size   Complexity  
A version() 0 5 1
A __construct() 0 4 1
A reset() 0 9 1
A makeTransaction() 0 4 1
A get() 0 4 1
A getAndReset() 0 6 1
A input() 0 13 3
A inputs() 0 8 1
A output() 0 5 1
A outputs() 0 8 1
A witnesses() 0 8 1
A locktime() 0 5 1
A lockToTimestamp() 0 5 1
A lockToBlockHeight() 0 5 1
A spendOutPoint() 0 10 2
A spendOutputFrom() 0 13 1
A payToAddress() 0 10 1
A bip69() 0 10 1
1
<?php
2
3
namespace BitWasp\Bitcoin\Transaction\Factory;
4
5
use BitWasp\Bitcoin\Address\AddressInterface;
6
use BitWasp\Bitcoin\Locktime;
7
use BitWasp\Bitcoin\Script\Script;
8
use BitWasp\Bitcoin\Script\ScriptFactory;
9
use BitWasp\Bitcoin\Script\ScriptInterface;
10
use BitWasp\Bitcoin\Script\ScriptWitnessInterface;
11
use BitWasp\Bitcoin\Transaction\Bip69\Bip69;
12
use BitWasp\Bitcoin\Transaction\OutPoint;
13
use BitWasp\Bitcoin\Transaction\OutPointInterface;
14
use BitWasp\Bitcoin\Transaction\Transaction;
15
use BitWasp\Bitcoin\Transaction\TransactionInput;
16
use BitWasp\Bitcoin\Transaction\TransactionInputInterface;
17
use BitWasp\Bitcoin\Transaction\TransactionInterface;
18
use BitWasp\Bitcoin\Transaction\TransactionOutput;
19
use BitWasp\Bitcoin\Transaction\TransactionOutputInterface;
20
use BitWasp\Buffertools\Buffer;
21
use BitWasp\Buffertools\BufferInterface;
22
23
class TxBuilder
24
{
25
    /**
26
     * @var int
27
     */
28
    private $nVersion;
29
30
    /**
31
     * @var array
32
     */
33
    private $inputs;
34
35
    /**
36
     * @var array
37
     */
38
    private $outputs;
39
40
    /**
41
     * @var array
42
     */
43
    private $witness;
44
45
    /**
46
     * @var int
47
     */
48
    private $nLockTime;
49
50 90
    public function __construct()
51
    {
52 90
        $this->reset();
53 90
    }
54
55
    /**
56
     * @return $this
57
     */
58 90
    public function reset()
59
    {
60 90
        $this->nVersion = 1;
61 90
        $this->inputs = [];
62 90
        $this->outputs = [];
63 90
        $this->witness = [];
64 90
        $this->nLockTime = 0;
65 90
        return $this;
66
    }
67
68
    /**
69
     * @return TransactionInterface
70
     */
71 87
    private function makeTransaction()
72
    {
73 87
        return new Transaction($this->nVersion, $this->inputs, $this->outputs, $this->witness, $this->nLockTime);
74
    }
75
76
    /**
77
     * @return TransactionInterface
78
     */
79 84
    public function get()
80
    {
81 84
        return $this->makeTransaction();
82
    }
83
84
    /**
85
     * @return TransactionInterface
86
     */
87 15
    public function getAndReset()
88
    {
89 15
        $transaction = $this->makeTransaction();
90 15
        $this->reset();
91 15
        return $transaction;
92
    }
93
94
    /**
95
     * @param int $nVersion
96
     * @return $this
97
     */
98 9
    public function version($nVersion)
99
    {
100 9
        $this->nVersion = $nVersion;
101 9
        return $this;
102
    }
103
104
    /**
105
     * @param BufferInterface|string $hashPrevOut - hex or BufferInterface
106
     * @param int $nPrevOut
107
     * @param Script|null $script
108
     * @param int $nSequence
109
     * @return $this
110
     */
111 45
    public function input($hashPrevOut, $nPrevOut, Script $script = null, $nSequence = TransactionInputInterface::SEQUENCE_FINAL)
112
    {
113 45
        $this->inputs[] = new TransactionInput(
114 45
            new OutPoint(
115 45
                $hashPrevOut instanceof BufferInterface ? $hashPrevOut : Buffer::hex($hashPrevOut, 32),
116
                $nPrevOut
117 30
            ),
118 45
            $script ?: new Script(),
119
            $nSequence
120 30
        );
121
122 45
        return $this;
123
    }
124
125
    /**
126
     * @param TransactionInputInterface[] $inputs
127
     * @return $this
128
     */
129
    public function inputs(array $inputs)
130
    {
131
        array_walk($inputs, function (TransactionInputInterface $input) {
132
            $this->inputs[] = $input;
133
        });
134
135
        return $this;
136
    }
137
138
    /**
139
     * @param integer $value
140
     * @param ScriptInterface $script
141
     * @return $this
142
     */
143 78
    public function output($value, ScriptInterface $script)
144
    {
145 78
        $this->outputs[] = new TransactionOutput($value, $script);
146 78
        return $this;
147
    }
148
149
    /**
150
     * @param TransactionOutputInterface[] $outputs
151
     * @return $this
152
     */
153
    public function outputs(array $outputs)
154
    {
155
        array_walk($outputs, function (TransactionOutputInterface $output) {
156
            $this->outputs[] = $output;
157
        });
158
159
        return $this;
160
    }
161
162
    /**
163
     * @param ScriptWitnessInterface[] $witness
164
     * @return $this
165
     */
166
    public function witnesses(array $witness)
167
    {
168
        array_walk($witness, function (ScriptWitnessInterface $witness) {
169
            $this->witness[] = $witness;
170
        });
171
172
        return $this;
173
    }
174
175
    /**
176
     * @param int $locktime
177
     * @return $this
178
     */
179 12
    public function locktime($locktime)
180
    {
181 12
        $this->nLockTime = $locktime;
182 12
        return $this;
183
    }
184
185
    /**
186
     * @param Locktime $lockTime
187
     * @param int $nTimestamp
188
     * @return $this
189
     * @throws \Exception
190
     */
191 3
    public function lockToTimestamp(Locktime $lockTime, $nTimestamp)
192
    {
193 3
        $this->locktime($lockTime->fromTimestamp($nTimestamp));
194 3
        return $this;
195
    }
196
197
    /**
198
     * @param Locktime $lockTime
199
     * @param int $blockHeight
200
     * @return $this
201
     * @throws \Exception
202
     */
203 3
    public function lockToBlockHeight(Locktime $lockTime, $blockHeight)
204
    {
205 3
        $this->locktime($lockTime->fromBlockHeight($blockHeight));
206 3
        return $this;
207
    }
208
209
    /**
210
     * @param OutPointInterface $outpoint
211
     * @param ScriptInterface|null $script
212
     * @param int $nSequence
213
     * @return $this
214
     */
215 27
    public function spendOutPoint(OutPointInterface $outpoint, ScriptInterface $script = null, $nSequence = TransactionInputInterface::SEQUENCE_FINAL)
216
    {
217 27
        $this->inputs[] = new TransactionInput(
218 18
            $outpoint,
219 27
            $script ?: new Script(),
220
            $nSequence
221 18
        );
222
223 27
        return $this;
224
    }
225
226
    /**
227
     * @param TransactionInterface $transaction
228
     * @param int $outputToSpend
229
     * @param ScriptInterface|null $script
230
     * @param int $nSequence
231
     * @return $this
232
     */
233 18
    public function spendOutputFrom(TransactionInterface $transaction, $outputToSpend, ScriptInterface $script = null, $nSequence = TransactionInputInterface::SEQUENCE_FINAL)
234
    {
235
        // Check TransactionOutput exists in $tx
236 18
        $transaction->getOutput($outputToSpend);
237 18
        $this->input(
238 18
            $transaction->getTxId(),
239 12
            $outputToSpend,
240 12
            $script,
0 ignored issues
show
Bug introduced by
It seems like $script defined by parameter $script on line 233 can also be of type object<BitWasp\Bitcoin\Script\ScriptInterface>; however, BitWasp\Bitcoin\Transact...tory\TxBuilder::input() does only seem to accept null|object<BitWasp\Bitcoin\Script\Script>, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
241
            $nSequence
242 12
        );
243
244 18
        return $this;
245
    }
246
247
    /**
248
     * Create an output paying $value to an Address.
249
     *
250
     * @param int $value
251
     * @param AddressInterface $address
252
     * @return $this
253
     */
254 42
    public function payToAddress($value, AddressInterface $address)
255
    {
256
        // Create Script from address, then create an output.
257 42
        $this->output(
258 28
            $value,
259 42
            ScriptFactory::scriptPubKey()->payToAddress($address)
260 28
        );
261
262 42
        return $this;
263
    }
264
265
    /**
266
     * Sorts the transaction inputs and outputs lexicographically,
267
     * according to BIP69
268
     *
269
     * @param Bip69 $bip69
270
     * @return $this
271
     */
272
    public function bip69(Bip69 $bip69)
273
    {
274
        list ($inputs, $witness) = $bip69->sortInputsAndWitness($this->inputs, $this->witness);
275
276
        $this->inputs = $inputs;
277
        $this->outputs = $bip69->sortOutputs($this->outputs);
278
        $this->witness = $witness;
279
280
        return $this;
281
    }
282
}
283