TransactionSerializer::fromParser()   B
last analyzed

Complexity

Conditions 10
Paths 24

Size

Total Lines 48
Code Lines 30

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 29
CRAP Score 10.0036

Importance

Changes 0
Metric Value
cc 10
eloc 30
nc 24
nop 1
dl 0
loc 48
ccs 29
cts 30
cp 0.9667
crap 10.0036
rs 7.6666
c 0
b 0
f 0

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace BitWasp\Bitcoin\Serializer\Transaction;
6
7
use BitWasp\Bitcoin\Script\Opcodes;
8
use BitWasp\Bitcoin\Serializer\Script\ScriptWitnessSerializer;
9
use BitWasp\Bitcoin\Serializer\Types;
10
use BitWasp\Bitcoin\Transaction\Transaction;
11
use BitWasp\Bitcoin\Transaction\TransactionInterface;
12
use BitWasp\Buffertools\BufferInterface;
13
use BitWasp\Buffertools\Parser;
14
15
class TransactionSerializer implements TransactionSerializerInterface
16
{
17
    const NO_WITNESS = 1;
18
19
    /**
20
     * @var \BitWasp\Buffertools\Types\Int32
21
     */
22
    protected $int32le;
23
24
    /**
25
     * @var \BitWasp\Buffertools\Types\Uint32
26
     */
27
    protected $uint32le;
28
29
    /**
30
     * @var \BitWasp\Buffertools\Types\VarInt
31
     */
32
    protected $varint;
33
34
    /**
35
     * @var TransactionInputSerializer
36
     */
37
    protected $inputSerializer;
38
39
    /**
40
     * @var TransactionOutputSerializer
41
     */
42
    protected $outputSerializer;
43
44
    /**
45
     * @var ScriptWitnessSerializer
46
     */
47
    protected $witnessSerializer;
48
49 5237
    public function __construct(TransactionInputSerializer $inputSerializer = null, TransactionOutputSerializer $outputSerializer = null, ScriptWitnessSerializer $witnessSerializer = null)
50
    {
51 5237
        $this->int32le = Types::int32le();
52 5237
        $this->uint32le = Types::uint32le();
53 5237
        $this->varint = Types::varint();
54
55 5237
        if ($inputSerializer === null || $outputSerializer === null) {
56 5236
            $opcodes = new Opcodes();
57 5236
            if (!$inputSerializer) {
58 5236
                $inputSerializer = new TransactionInputSerializer(new OutPointSerializer(), $opcodes);
59
            }
60 5236
            if (!$outputSerializer) {
61 5236
                $outputSerializer = new TransactionOutputSerializer($opcodes);
62
            }
63
        }
64
65 5237
        if (!$witnessSerializer) {
66 5236
            $witnessSerializer = new ScriptWitnessSerializer();
67
        }
68
69 5237
        $this->inputSerializer = $inputSerializer;
70 5237
        $this->outputSerializer = $outputSerializer;
71 5237
        $this->witnessSerializer = $witnessSerializer;
72 5237
    }
73
74
    /**
75
     * @param Parser $parser
76
     * @return TransactionInterface
77
     */
78 60
    public function fromParser(Parser $parser): TransactionInterface
79
    {
80 60
        $version = (int) $this->int32le->read($parser);
81
82 60
        $vin = [];
83 60
        $vinCount = $this->varint->read($parser);
84 60
        for ($i = 0; $i < $vinCount; $i++) {
85 49
            $vin[] = $this->inputSerializer->fromParser($parser);
86
        }
87
88 60
        $vout = [];
89 60
        $flags = 0;
90 60
        if (count($vin) === 0) {
91 11
            $flags = (int) $this->varint->read($parser);
92 11
            if ($flags !== 0) {
93 11
                $vinCount = $this->varint->read($parser);
94 11
                for ($i = 0; $i < $vinCount; $i++) {
95 11
                    $vin[] = $this->inputSerializer->fromParser($parser);
96
                }
97
98 11
                $voutCount = $this->varint->read($parser);
99 11
                for ($i = 0; $i < $voutCount; $i++) {
100 11
                    $vout[] = $this->outputSerializer->fromParser($parser);
101
                }
102
            }
103
        } else {
104 49
            $voutCount = $this->varint->read($parser);
105 49
            for ($i = 0; $i < $voutCount; $i++) {
106 49
                $vout[] = $this->outputSerializer->fromParser($parser);
107
            }
108
        }
109
110 59
        $vwit = [];
111 59
        if (($flags & 1)) {
112 11
            $flags ^= 1;
113 11
            $witCount = count($vin);
114 11
            for ($i = 0; $i < $witCount; $i++) {
115 11
                $vwit[] = $this->witnessSerializer->fromParser($parser);
116
            }
117
        }
118
119 59
        if ($flags) {
120
            throw new \RuntimeException('Flags byte was 0');
121
        }
122
123 59
        $lockTime = (int) $this->uint32le->read($parser);
124
125 59
        return new Transaction($version, $vin, $vout, $vwit, $lockTime);
126
    }
127
128
    /**
129
     * @param BufferInterface $data
130
     * @return TransactionInterface
131
     */
132 49
    public function parse(BufferInterface $data): TransactionInterface
133
    {
134 49
        return $this->fromParser(new Parser($data));
135
    }
136
137
    /**
138
     * @param TransactionInterface $transaction
139
     * @param int $opt
140
     * @return BufferInterface
141
     */
142 5228
    public function serialize(TransactionInterface $transaction, int $opt = 0): BufferInterface
143
    {
144 5228
        $parser = new Parser();
145 5228
        $parser->appendBinary($this->int32le->write($transaction->getVersion()));
146
147 5228
        $flags = 0;
148 5228
        $allowWitness = !($opt & self::NO_WITNESS);
149 5228
        if ($allowWitness && $transaction->hasWitness()) {
150 130
            $flags |= 1;
151
        }
152
153 5228
        if ($flags) {
154 130
            $parser->appendBinary(pack("CC", 0, $flags));
155
        }
156
157 5228
        $parser->appendBinary($this->varint->write(count($transaction->getInputs())));
158 5228
        foreach ($transaction->getInputs() as $input) {
159 5227
            $parser->appendBuffer($this->inputSerializer->serialize($input));
160
        }
161
162 5228
        $parser->appendBinary($this->varint->write(count($transaction->getOutputs())));
163 5228
        foreach ($transaction->getOutputs() as $output) {
164 5228
            $parser->appendBuffer($this->outputSerializer->serialize($output));
165
        }
166
167 5228
        if ($flags & 1) {
168 130
            foreach ($transaction->getWitnesses() as $witness) {
169 130
                $parser->appendBuffer($this->witnessSerializer->serialize($witness));
170
            }
171
        }
172
173 5228
        $parser->appendBinary($this->uint32le->write($transaction->getLockTime()));
174
175 5228
        return $parser->getBuffer();
176
    }
177
}
178