Completed
Push — master ( abcf31...a8a46d )
by thomas
28:08 queued 25:46
created

TxBuilder::spendOutPoint()   A

Complexity

Conditions 2
Paths 1

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 6
nc 1
nop 3
dl 0
loc 10
ccs 6
cts 6
cp 1
crap 2
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace BitWasp\Bitcoin\Transaction\Factory;
6
7
use BitWasp\Bitcoin\Address\AddressInterface;
8
use BitWasp\Bitcoin\Locktime;
9
use BitWasp\Bitcoin\Script\Script;
10
use BitWasp\Bitcoin\Script\ScriptFactory;
11
use BitWasp\Bitcoin\Script\ScriptInterface;
12
use BitWasp\Bitcoin\Script\ScriptWitnessInterface;
13
use BitWasp\Bitcoin\Transaction\Bip69\Bip69;
14
use BitWasp\Bitcoin\Transaction\OutPoint;
15
use BitWasp\Bitcoin\Transaction\OutPointInterface;
16
use BitWasp\Bitcoin\Transaction\Transaction;
17
use BitWasp\Bitcoin\Transaction\TransactionInput;
18
use BitWasp\Bitcoin\Transaction\TransactionInputInterface;
19
use BitWasp\Bitcoin\Transaction\TransactionInterface;
20
use BitWasp\Bitcoin\Transaction\TransactionOutput;
21
use BitWasp\Bitcoin\Transaction\TransactionOutputInterface;
22
use BitWasp\Buffertools\Buffer;
23
use BitWasp\Buffertools\BufferInterface;
24
25
class TxBuilder
26
{
27
    /**
28
     * @var int
29
     */
30
    private $nVersion;
31
32
    /**
33
     * @var array
34
     */
35
    private $inputs;
36
37
    /**
38
     * @var array
39
     */
40
    private $outputs;
41
42
    /**
43
     * @var array
44
     */
45
    private $witness;
46
47
    /**
48
     * @var int
49
     */
50
    private $nLockTime;
51
52 35
    public function __construct()
53
    {
54 35
        $this->reset();
55 35
    }
56
57
    /**
58
     * @return $this
59
     */
60 35
    public function reset()
61
    {
62 35
        $this->nVersion = 1;
63 35
        $this->inputs = [];
64 35
        $this->outputs = [];
65 35
        $this->witness = [];
66 35
        $this->nLockTime = 0;
67 35
        return $this;
68
    }
69
70
    /**
71
     * @return TransactionInterface
72
     */
73 84
    private function makeTransaction(): TransactionInterface
74
    {
75 84
        return new Transaction($this->nVersion, $this->inputs, $this->outputs, $this->witness, $this->nLockTime);
76
    }
77
78
    /**
79
     * @return TransactionInterface
80
     */
81 83
    public function get(): TransactionInterface
82
    {
83 83
        return $this->makeTransaction();
84
    }
85
86
    /**
87
     * @return TransactionInterface
88
     */
89 2
    public function getAndReset(): TransactionInterface
90
    {
91 2
        $transaction = $this->makeTransaction();
92 2
        $this->reset();
93 2
        return $transaction;
94
    }
95
96
    /**
97
     * @param int $nVersion
98
     * @return $this
99
     */
100 5
    public function version(int $nVersion)
101
    {
102 5
        $this->nVersion = $nVersion;
103 5
        return $this;
104
    }
105
106
    /**
107
     * @param BufferInterface|string $hashPrevOut - hex or BufferInterface
108
     * @param int $nPrevOut
109
     * @param Script|null $script
110
     * @param int $nSequence
111
     * @return $this
112
     */
113 16
    public function input($hashPrevOut, int $nPrevOut, Script $script = null, int $nSequence = TransactionInputInterface::SEQUENCE_FINAL)
114
    {
115 16
        if ($hashPrevOut instanceof BufferInterface) {
116 3
            if ($hashPrevOut->getSize() !== 32) {
117 3
                throw new \InvalidArgumentException("Invalid size for txid buffer");
118
            }
119 13
        } else if (is_string($hashPrevOut)) {
120 13
            $hashPrevOut = Buffer::hex($hashPrevOut, 32);
121
        } else {
122
            throw new \InvalidArgumentException("Invalid value for hashPrevOut in TxBuilder::input");
123
        }
124
125 16
        $this->inputs[] = new TransactionInput(
126 16
            new OutPoint($hashPrevOut, $nPrevOut),
127 16
            $script ?: new Script(),
128 16
            $nSequence
129
        );
130
131 16
        return $this;
132
    }
133
134
    /**
135
     * @param TransactionInputInterface[] $inputs
136
     * @return $this
137
     */
138
    public function inputs(array $inputs)
139
    {
140 7
        array_walk($inputs, function (TransactionInputInterface $input) {
141 7
            $this->inputs[] = $input;
142 7
        });
143
144 7
        return $this;
145
    }
146
147
    /**
148
     * @param integer $value
149
     * @param ScriptInterface $script
150
     * @return $this
151
     */
152 24
    public function output(int $value, ScriptInterface $script)
153
    {
154 24
        $this->outputs[] = new TransactionOutput($value, $script);
155 24
        return $this;
156
    }
157
158
    /**
159
     * @param TransactionOutputInterface[] $outputs
160
     * @return $this
161
     */
162
    public function outputs(array $outputs)
163
    {
164 7
        array_walk($outputs, function (TransactionOutputInterface $output) {
165 7
            $this->outputs[] = $output;
166 7
        });
167
168 7
        return $this;
169
    }
170
171
    /**
172
     * @param ScriptWitnessInterface[] $witness
173
     * @return $this
174
     */
175
    public function witnesses(array $witness)
176
    {
177
        array_walk($witness, function (ScriptWitnessInterface $witness) {
178
            $this->witness[] = $witness;
179
        });
180
181
        return $this;
182
    }
183
184
    /**
185
     * @param int $locktime
186
     * @return $this
187
     */
188 4
    public function locktime(int $locktime)
189
    {
190 4
        $this->nLockTime = $locktime;
191 4
        return $this;
192
    }
193
194
    /**
195
     * @param Locktime $lockTime
196
     * @param int $nTimestamp
197
     * @return $this
198
     * @throws \Exception
199
     */
200 1
    public function lockToTimestamp(Locktime $lockTime, int $nTimestamp)
201
    {
202 1
        $this->locktime($lockTime->fromTimestamp($nTimestamp));
203 1
        return $this;
204
    }
205
206
    /**
207
     * @param Locktime $lockTime
208
     * @param int $blockHeight
209
     * @return $this
210
     * @throws \Exception
211
     */
212 1
    public function lockToBlockHeight(Locktime $lockTime, int $blockHeight)
213
    {
214 1
        $this->locktime($lockTime->fromBlockHeight($blockHeight));
215 1
        return $this;
216
    }
217
218
    /**
219
     * @param OutPointInterface $outpoint
220
     * @param ScriptInterface|null $script
221
     * @param int $nSequence
222
     * @return $this
223
     */
224 6
    public function spendOutPoint(OutPointInterface $outpoint, ScriptInterface $script = null, int $nSequence = TransactionInputInterface::SEQUENCE_FINAL)
225
    {
226 6
        $this->inputs[] = new TransactionInput(
227 6
            $outpoint,
228 6
            $script ?: new Script(),
229 6
            $nSequence
230
        );
231
232 6
        return $this;
233
    }
234
235
    /**
236
     * @param TransactionInterface $transaction
237
     * @param int $outputToSpend
238
     * @param ScriptInterface|null $script
239
     * @param int $nSequence
240
     * @return $this
241
     */
242 1
    public function spendOutputFrom(TransactionInterface $transaction, int $outputToSpend, ScriptInterface $script = null, int $nSequence = TransactionInputInterface::SEQUENCE_FINAL)
243
    {
244
        // Check TransactionOutput exists in $tx
245 1
        $transaction->getOutput($outputToSpend);
246 1
        $this->input(
247 1
            $transaction->getTxId(),
248 1
            $outputToSpend,
249 1
            $script,
0 ignored issues
show
Bug introduced by
It seems like $script defined by parameter $script on line 242 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...
250 1
            $nSequence
251
        );
252
253 1
        return $this;
254
    }
255
256
    /**
257
     * Create an output paying $value to an Address.
258
     *
259
     * @param int $value
260
     * @param AddressInterface $address
261
     * @return $this
262
     */
263 8
    public function payToAddress(int $value, AddressInterface $address)
264
    {
265
        // Create Script from address, then create an output.
266 8
        $this->output(
267 8
            $value,
268 8
            $address->getScriptPubKey()
269
        );
270
271 8
        return $this;
272
    }
273
274
    /**
275
     * Sorts the transaction inputs and outputs lexicographically,
276
     * according to BIP69
277
     *
278
     * @param Bip69 $bip69
279
     * @return $this
280
     */
281
    public function bip69(Bip69 $bip69)
282
    {
283
        list ($inputs, $witness) = $bip69->sortInputsAndWitness($this->inputs, $this->witness);
284
285
        $this->inputs = $inputs;
286
        $this->outputs = $bip69->sortOutputs($this->outputs);
287
        $this->witness = $witness;
288
289
        return $this;
290
    }
291
}
292