Completed
Push — master ( 2dcc62...2dcc62 )
by thomas
151:35 queued 116:37
created

NetworkMessageSerializer::parsePacket()   D

Complexity

Conditions 26
Paths 50

Size

Total Lines 91
Code Lines 82

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 79
CRAP Score 26

Importance

Changes 0
Metric Value
dl 0
loc 91
ccs 79
cts 79
cp 1
rs 4.5382
c 0
b 0
f 0
cc 26
eloc 82
nc 50
nop 2
crap 26

How to fix   Long Method    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
namespace BitWasp\Bitcoin\Networking\Serializer;
4
5
use BitWasp\Bitcoin\Bitcoin;
6
use BitWasp\Bitcoin\Crypto\Hash;
7
use BitWasp\Bitcoin\Network\NetworkInterface;
8
use BitWasp\Bitcoin\Networking\Message;
9
use BitWasp\Bitcoin\Networking\Messages\Block;
10
use BitWasp\Bitcoin\Networking\Messages\FilterClear;
11
use BitWasp\Bitcoin\Networking\Messages\GetAddr;
12
use BitWasp\Bitcoin\Networking\Messages\MemPool;
13
use BitWasp\Bitcoin\Networking\Messages\SendHeaders;
14
use BitWasp\Bitcoin\Networking\Messages\Tx;
15
use BitWasp\Bitcoin\Networking\Messages\VerAck;
16
use BitWasp\Bitcoin\Networking\NetworkMessage;
17
use BitWasp\Bitcoin\Networking\Serializer\Message\AddrSerializer;
18
use BitWasp\Bitcoin\Networking\Serializer\Message\AlertSerializer;
19
use BitWasp\Bitcoin\Networking\Serializer\Message\FeeFilterSerializer;
20
use BitWasp\Bitcoin\Networking\Serializer\Message\FilterAddSerializer;
21
use BitWasp\Bitcoin\Networking\Serializer\Message\FilterLoadSerializer;
22
use BitWasp\Bitcoin\Networking\Serializer\Message\GetBlocksSerializer;
23
use BitWasp\Bitcoin\Networking\Serializer\Message\GetDataSerializer;
24
use BitWasp\Bitcoin\Networking\Serializer\Message\GetHeadersSerializer;
25
use BitWasp\Bitcoin\Networking\Serializer\Message\HeadersSerializer;
26
use BitWasp\Bitcoin\Networking\Serializer\Message\InvSerializer;
27
use BitWasp\Bitcoin\Networking\Serializer\Message\MerkleBlockSerializer;
28
use BitWasp\Bitcoin\Networking\Serializer\Message\NotFoundSerializer;
29
use BitWasp\Bitcoin\Networking\Serializer\Message\PingSerializer;
30
use BitWasp\Bitcoin\Networking\Serializer\Message\PongSerializer;
31
use BitWasp\Bitcoin\Networking\Serializer\Message\RejectSerializer;
32
use BitWasp\Bitcoin\Networking\Serializer\Message\VersionSerializer;
33
use BitWasp\Bitcoin\Networking\Serializer\Structure\AlertDetailSerializer;
34
use BitWasp\Bitcoin\Networking\Serializer\Structure\HeaderSerializer;
35
use BitWasp\Bitcoin\Networking\Serializer\Structure\InventorySerializer;
36
use BitWasp\Bitcoin\Networking\Serializer\Structure\NetworkAddressSerializer;
37
use BitWasp\Bitcoin\Networking\Serializer\Structure\NetworkAddressTimestampSerializer;
38
use BitWasp\Bitcoin\Networking\Structure\Header;
39
use BitWasp\Bitcoin\Serializer\Bloom\BloomFilterSerializer;
40
use BitWasp\Bitcoin\Serializer\Block\FilteredBlockSerializer;
41
use BitWasp\Bitcoin\Serializer\Block\BlockHeaderSerializer;
42
use BitWasp\Bitcoin\Serializer\Block\BlockSerializer;
43
use BitWasp\Bitcoin\Serializer\Block\PartialMerkleTreeSerializer;
44
use BitWasp\Bitcoin\Serializer\Chain\BlockLocatorSerializer;
45
use BitWasp\Bitcoin\Serializer\Transaction\TransactionSerializer;
46
use BitWasp\Bitcoin\Serializer\Types;
47
use BitWasp\Buffertools\Parser;
48
use BitWasp\Buffertools\Buffer;
49
50
class NetworkMessageSerializer
51
{
52
    /**
53
     * @var NetworkInterface
54
     */
55
    private $network;
56
57
    /**
58
     * @var \BitWasp\Bitcoin\Math\Math
59
     */
60
    private $math;
61
62
    /**
63
     * @var TransactionSerializer
64
     */
65
    private $txSerializer;
66
67
    /**
68
     * @var BlockHeaderSerializer
69
     */
70
    private $headerSerializer;
71
72
    /**
73
     * @var GetDataSerializer
74
     */
75
    private $getDataSerializer;
76
77
    /**
78
     * @var InvSerializer
79
     */
80
    private $invSerializer;
81
82
    /**
83
     * @var BlockSerializer
84
     */
85
    private $blockSerializer;
86
87
    /**
88
     * @var FilteredBlockSerializer
89
     */
90
    private $filteredBlockSerializer;
91
92
    /**
93
     * @var HeadersSerializer
94
     */
95
    private $headersSerializer;
96
97
    /**
98
     * @var FilterAddSerializer
99
     */
100
    private $filterAddSerializer;
101
102
    /**
103
     * @var FilterLoadSerializer
104
     */
105
    private $filterLoadSerializer;
106
107
    /**
108
     * @var MerkleBlockSerializer
109
     */
110
    private $merkleBlockSerializer;
111
112
    /**
113
     * @var PingSerializer
114
     */
115
    private $pingSerializer;
116
117
    /**
118
     * @var AlertSerializer
119
     */
120
    private $alertSerializer;
121
122
    /**
123
     * @var InventorySerializer
124
     */
125
    private $inventorySerializer;
126
127
    /**
128
     * @var NotFoundSerializer
129
     */
130
    private $notFoundSerializer;
131
132
    /**
133
     * @var RejectSerializer
134
     */
135
    private $rejectSerializer;
136
137
    /**
138
     * @var BlockLocatorSerializer
139
     */
140
    private $blockLocatorSerializer;
141
142
    /**
143
     * @var GetBlocksSerializer
144
     */
145
    private $getBlocksSerializer;
146
147
    /**
148
     * @var GetHeadersSerializer
149
     */
150
    private $getHeadersSerializer;
151
152
    /**
153
     * @var PongSerializer
154
     */
155
    private $pongSerializer;
156
157
    /**
158
     * @var VersionSerializer
159
     */
160
    private $versionSerializer;
161
162
    /**
163
     * @var FeeFilterSerializer
164
     */
165
    private $feeFilterSerializer;
166
167
    /**
168
     * @var AddrSerializer
169
     */
170
    private $addrSerializer;
171
172
    /**
173
     * @param NetworkInterface $network
174 96
     */
175
    public function __construct(NetworkInterface $network)
176 96
    {
177 96
        $this->math = Bitcoin::getMath();
178 96
        $this->network = $network;
179 96
        $this->bs4le = Types::bytestringle(4);
0 ignored issues
show
Bug introduced by
The property bs4le does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
180 96
        $this->txSerializer = new TransactionSerializer();
181 96
        $this->headerSerializer = new BlockHeaderSerializer();
182 96
        $this->blockSerializer = new BlockSerializer($this->math, $this->headerSerializer, $this->txSerializer);
183 96
        $this->filteredBlockSerializer = new FilteredBlockSerializer($this->headerSerializer, new PartialMerkleTreeSerializer());
184 96
        $this->headersSerializer = new HeadersSerializer($this->headerSerializer);
185 96
        $this->filterAddSerializer = new FilterAddSerializer();
186 96
        $this->filterLoadSerializer = new FilterLoadSerializer(new BloomFilterSerializer());
187 96
        $this->merkleBlockSerializer = new MerkleBlockSerializer($this->filteredBlockSerializer);
188 96
        $this->pingSerializer = new PingSerializer();
189 96
        $this->pongSerializer = new PongSerializer();
190 96
        $this->alertSerializer = new AlertSerializer(new AlertDetailSerializer());
191 96
        $this->inventorySerializer = new InventorySerializer();
192 96
        $this->getDataSerializer = new GetDataSerializer($this->inventorySerializer);
193 96
        $this->invSerializer = new InvSerializer($this->inventorySerializer);
194 96
        $this->notFoundSerializer = new NotFoundSerializer($this->inventorySerializer);
195 96
        $this->feeFilterSerializer = new FeeFilterSerializer();
196 96
        $this->rejectSerializer = new RejectSerializer();
197 96
        $this->blockLocatorSerializer = new BlockLocatorSerializer();
198 96
        $this->getBlocksSerializer = new GetBlocksSerializer($this->blockLocatorSerializer);
199 96
        $this->getHeadersSerializer = new GetHeadersSerializer($this->blockLocatorSerializer);
200 96
        $this->versionSerializer = new VersionSerializer(new NetworkAddressSerializer());
201
        $this->addrSerializer = new AddrSerializer(new NetworkAddressTimestampSerializer());
202
        $this->packetHeaderSerializer = new HeaderSerializer();
0 ignored issues
show
Bug introduced by
The property packetHeaderSerializer does not seem to exist. Did you mean headerSerializer?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
203
    }
204
205 96
    /**
206
     * @param Parser $parser
207 96
     * @return Header
208 96
     */
209 96
    public function parseHeader(Parser $parser)
210 96
    {
211 96
        $prefix = $this->bs4le->read($parser);
212 96
        if ($prefix->getHex() !== $this->network->getNetMagicBytes()) {
213
            throw new \RuntimeException('Invalid magic bytes for network');
214
        }
215
216
        return $this->packetHeaderSerializer->fromParser($parser);
0 ignored issues
show
Bug introduced by
The property packetHeaderSerializer does not seem to exist. Did you mean headerSerializer?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
217
    }
218
219
    /**
220
     * @param Header $header
221 90
     * @param Parser $parser
222
     * @return NetworkMessage
223 90
     */
224
    public function parsePacket(Header $header, Parser $parser)
225
    {
226
        $buffer = $header->getLength() > 0
227
            ? $parser->readBytes($header->getLength())
228
            : new Buffer('', 0, $this->math);
229 90
230 3
        // Compare payload checksum against header value
231
        if (!Hash::sha256d($buffer)->slice(0, 4)->equals($header->getChecksum())) {
232
            throw new \RuntimeException('Invalid packet checksum');
233 29
        }
234 81
235 87
        $cmd = trim($header->getCommand());
236
        switch ($cmd) {
237
            case Message::VERSION:
238 87
                $payload = $this->versionSerializer->parse($buffer);
239 3
                break;
240
            case Message::VERACK:
241
                $payload = new VerAck();
242 84
                break;
243
            case Message::SENDHEADERS:
244 84
                $payload = new SendHeaders();
245 15
                break;
246 15
            case Message::ADDR:
247 81
                $payload = $this->addrSerializer->parse($buffer);
248 15
                break;
249 15
            case Message::INV:
250 69
                $payload = $this->invSerializer->parse($buffer);
251 3
                break;
252 3
            case Message::GETDATA:
253 66
                $payload = $this->getDataSerializer->parse($buffer);
254 5
                break;
255 5
            case Message::NOTFOUND:
256 63
                $payload = $this->notFoundSerializer->parse($buffer);
257 3
                break;
258 3
            case Message::GETBLOCKS:
259 60
                $payload = $this->getBlocksSerializer->parse($buffer);
260 3
                break;
261 3
            case Message::GETHEADERS:
262 57
                $payload = $this->getHeadersSerializer->parse($buffer);
263 3
                break;
264 3
            case Message::TX:
265 54
                $payload = new Tx($this->txSerializer->parse($buffer));
266 3
                break;
267 3
            case Message::BLOCK:
268 51
                $payload = new Block($this->blockSerializer->parse($buffer));
269 3
                break;
270 3
            case Message::HEADERS:
271 48
                $payload = $this->headersSerializer->parse($buffer);
272 3
                break;
273 3
            case Message::GETADDR:
274 45
                $payload = new GetAddr();
275 3
                break;
276 3
            case Message::MEMPOOL:
277 42
                $payload = new MemPool();
278 3
                break;
279 3
            case Message::FEEFILTER:
280 39
                $payload = $this->feeFilterSerializer->parse($buffer);
281 3
                break;
282 3
            case Message::FILTERLOAD:
283 36
                $payload = $this->filterLoadSerializer->parse($buffer);
284 3
                break;
285 3
            case Message::FILTERADD:
286 33
                $payload = $this->filterAddSerializer->parse($buffer);
287 3
                break;
288 3
            case Message::FILTERCLEAR:
289 30
                $payload = new FilterClear();
290 3
                break;
291 3
            case Message::MERKLEBLOCK:
292 27
                $payload = $this->merkleBlockSerializer->parse($buffer);
293 3
                break;
294 3
            case Message::PING:
295 24
                $payload = $this->pingSerializer->parse($buffer);
296 3
                break;
297 3
            case Message::PONG:
298 21
                $payload = $this->pongSerializer->parse($buffer);
299 3
                break;
300 3
            case Message::REJECT:
301 18
                $payload = $this->rejectSerializer->parse($buffer);
302 6
                break;
303 6
            case Message::ALERT:
304 12
                $payload = $this->alertSerializer->parse($buffer);
305 3
                break;
306 3
            default:
307 9
                throw new \RuntimeException('Invalid command');
308 3
        }
309 3
310 6
        return new NetworkMessage(
311 3
            $this->network,
312 3
            $payload
313 2
        );
314 3
    }
315 2
316
    /**
317 81
     * @param Parser $parser
318 81
     * @return NetworkMessage
319
     * @throws \BitWasp\Buffertools\Exceptions\ParserOutOfRange
320 54
     * @throws \Exception
321
     */
322
    public function fromParser(Parser $parser)
323
    {
324
        $header = $this->parseHeader($parser);
325
        return $this->parsePacket($header, $parser);
326
    }
327 96
328
    /**
329 96
     * @param NetworkMessage $object
330 96
     * @return Buffer
331 96
     */
332 96
    public function serialize(NetworkMessage $object)
333 96
    {
334 96
        $prefix = $this->bs4le->write(Buffer::hex($this->network->getNetMagicBytes(), null, $this->math));
335 96
        $header = $this->packetHeaderSerializer->serialize($object->getHeader());
0 ignored issues
show
Bug introduced by
The property packetHeaderSerializer does not seem to exist. Did you mean headerSerializer?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
336 64
        $payload = $object->getPayload()->getBuffer();
337
338 96
        return new Buffer(
339
            "{$prefix}{$header->getBinary()}{$payload->getBinary()}"
340
        );
341
    }
342
343
    /**
344
     * @param $data
345
     * @return NetworkMessage
346 54
     * @throws \Exception
347
     */
348 54
    public function parse($data)
349
    {
350
        return $this->fromParser(new Parser($data, $this->math));
351
    }
352
}
353