Completed
Pull Request — master (#85)
by thomas
04:06
created

Peer::version()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 21
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 21
ccs 0
cts 12
cp 0
rs 9.3142
cc 1
eloc 18
nc 1
nop 8
crap 2

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
namespace BitWasp\Bitcoin\Networking\Peer;
4
5
use BitWasp\Bitcoin\Block\BlockInterface;
6
use BitWasp\Bitcoin\Block\FilteredBlock;
7
use BitWasp\Bitcoin\Bloom\BloomFilter;
8
use BitWasp\Bitcoin\Chain\BlockLocator;
9
use BitWasp\Bitcoin\Networking\Message;
10
use BitWasp\Bitcoin\Networking\Messages\Version;
11
use BitWasp\Bitcoin\Networking\Messages\Ping;
12
use BitWasp\Bitcoin\Networking\NetworkMessage;
13
use BitWasp\Bitcoin\Networking\NetworkSerializable;
14
use BitWasp\Bitcoin\Networking\Structure\AlertDetail;
15
use BitWasp\Bitcoin\Networking\Structure\Header;
16
use BitWasp\Bitcoin\Networking\Structure\Inventory;
17
use BitWasp\Bitcoin\Networking\Structure\NetworkAddressInterface;
18
use BitWasp\Bitcoin\Networking\Structure\NetworkAddressTimestamp;
19
use BitWasp\Bitcoin\Crypto\EcAdapter\Signature\SignatureInterface;
20
use BitWasp\Bitcoin\Transaction\TransactionInterface;
21
use BitWasp\Buffertools\Buffer;
22
use BitWasp\Buffertools\BufferInterface;
23
use BitWasp\Buffertools\Parser;
24
use Evenement\EventEmitter;
25
use React\EventLoop\LoopInterface;
26
use React\Promise\Deferred;
27
use React\Socket\ConnectionInterface;
28
use React\Stream\Stream;
29
30
class Peer extends EventEmitter
31
{
32
    /**
33
     * @var string
34
     */
35
    private $buffer = '';
36
37
    /**
38
     * @var LoopInterface
39
     */
40
    private $loop;
41
42
    /**
43
     * @var \BitWasp\Bitcoin\Networking\Messages\Factory
44
     */
45
    private $msgs;
46
47
    /**
48
     * @var Stream
49
     */
50
    private $stream;
51
52
    /**
53
     * @var Version
54
     */
55
    private $localVersion;
56
57
    /**
58
     * @var Version
59
     */
60
    private $remoteVersion;
61
62
    /**
63
     * @var NetworkAddressInterface
64
     */
65
    private $peerAddress;
66
67
    /**
68
     * @var ConnectionParams
69
     */
70
    private $connectionParams;
71
72
    /**
73
     * @var bool
74
     */
75
    private $exchangedVersion = false;
76
77
    /**
78
     * @var Header
79
     */
80
    private $incomingMsgHeader;
81
82
    /**
83
     * @param \BitWasp\Bitcoin\Networking\Messages\Factory $msgs
84
     * @param LoopInterface $loop
85
     */
86 11
    public function __construct(\BitWasp\Bitcoin\Networking\Messages\Factory $msgs, LoopInterface $loop)
87
    {
88 11
        $this->msgs = $msgs;
89 11
        $this->loop = $loop;
90 11
    }
91
92
    /**
93
     * @return Version
94
     */
95 3
    public function getLocalVersion()
96
    {
97 3
        return $this->localVersion;
98
    }
99
100
    /**
101
     * @return Version
102
     */
103 3
    public function getRemoteVersion()
104
    {
105 3
        return $this->remoteVersion;
106
    }
107
108
    /**
109
     * Reliably returns the remote peers NetAddr when known through
110
     * the connection process. Often better than the data contained
111
     * in a Version message.
112
     *
113
     * @return NetworkAddressInterface
114
     */
115 3
    public function getRemoteAddress()
116
    {
117 3
        return $this->peerAddress;
118
    }
119
120
    /**
121
     * @return ConnectionParams
122
     */
123 3
    public function getConnectionParams()
124
    {
125 3
        return $this->connectionParams;
126
    }
127
128
    /**
129
     * @param NetworkSerializable $msg
130
     */
131 11
    public function send(NetworkSerializable $msg)
132
    {
133 11
        $netMsg = $msg->getNetworkMessage($this->msgs->getNetwork());
134 11
        $serialized = $this->msgs->getSerializer()->serialize($netMsg);
135 11
        $this->stream->write($serialized->getBinary());
136 11
        $this->emit('send', [$netMsg]);
137 11
    }
138
139
    /**
140
     * @param Stream $stream
141
     * @return $this
142
     */
143 11
    public function setupStream(ConnectionInterface $stream)
144
    {
145 11
        $this->stream = $stream;
0 ignored issues
show
Documentation Bug introduced by
It seems like $stream of type object<React\Socket\ConnectionInterface> is incompatible with the declared type object<React\Stream\Stream> of property $stream.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
146
        $this->stream->on('data', function ($data) {
147 11
            $this->buffer .= $data;
148
149 11
            $data = new Buffer($this->buffer);
150 11
            $parser = new Parser($data);
151
152 11
            $pos = $parser->getPosition();
153 11
            $sz = $parser->getSize();
154
155
            try {
156 11
                while ($pos < $sz) {
157 11
                    if (null === $this->incomingMsgHeader) {
158 11
                        if ($sz - $pos < 24) {
159
                            break;
160
                        }
161
162 11
                        $this->incomingMsgHeader = $this->msgs->getSerializer()->parseHeader($parser);
163 11
                        $pos = $parser->getPosition();
164 4
                    }
165
166 11
                    if ($sz - $pos < $this->incomingMsgHeader->getLength()) {
167
                        break;
168
                    }
169
170 11
                    $message = $this->msgs->getSerializer()->parsePacket($this->incomingMsgHeader, $parser);
171 11
                    $this->incomingMsgHeader = null;
172 11
                    $this->emit('msg', [$this, $message]);
173 11
                    $pos = $parser->getPosition();
174 4
                }
175 4
            } catch (\Exception $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
176
177
            }
178
179 11
            $this->buffer = $parser->getBuffer()->slice($pos)->getBinary();
180 11
        });
181
182
        $this->stream->once('close', function () {
183 6
            $this->close();
184 11
        });
185
186
        $this->on('msg', function (Peer $peer, NetworkMessage $msg) {
187 11
            $this->emit($msg->getCommand(), [$peer, $msg->getPayload()]);
188 11
        });
189
190 11
        return $this;
191
    }
192
193
    /**
194
     * @param ConnectionInterface $connection
195
     * @param ConnectionParams $params
196
     * @return \React\Promise\Promise|\React\Promise\PromiseInterface
197
     */
198 9
    public function inboundHandshake(ConnectionInterface $connection, ConnectionParams $params)
0 ignored issues
show
Unused Code introduced by
The parameter $connection is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
199
    {
200 9
        $this->connectionParams = $params;
201
202 9
        $deferred = new Deferred();
203
        $this->on(Message::VERSION, function (Peer $peer, Version $version) use ($params) {
204 9
            $this->peerAddress = $version->getSenderAddress();
205 9
            $this->remoteVersion = $version;
206 9
            $this->localVersion = $localVersion = $params->produceVersion($this->msgs, $version->getSenderAddress());
207 9
            $this->send($localVersion);
208 9
        });
209
210
        $this->on(Message::VERACK, function () use ($deferred) {
211 9
            if (false === $this->exchangedVersion) {
212 9
                $this->exchangedVersion = true;
213 9
                $this->verack();
214 9
                $this->emit('ready', [$this]);
215 9
                $deferred->resolve($this);
216 3
            }
217 9
        });
218
219 9
        return $deferred->promise();
220
    }
221
222
    /**
223
     * @param NetworkAddressInterface $remotePeer
224
     * @param ConnectionParams $params
225
     * @return \React\Promise\Promise|\React\Promise\PromiseInterface
226
     */
227 11
    public function outboundHandshake(NetworkAddressInterface $remotePeer, ConnectionParams $params)
228
    {
229 11
        $deferred = new Deferred();
230
        
231 11
        $awaitVersion = true;
232
        $this->stream->once('close', function () use (&$awaitVersion, $deferred) {
233 6
            if ($awaitVersion) {
234 6
                $awaitVersion = false;
235 6
                $deferred->reject(new \Exception('peer disconnected'));
236 2
            }
237 11
        });
238
239
        $this->on(Message::VERSION, function (Peer $peer, Version $version) use ($params) {
240 11
            $this->remoteVersion = $version;
241 11
            $this->verack();
242 11
        });
243
244 11
        $this->on(Message::VERACK, function () use ($deferred) {
245 8
            if (false === $this->exchangedVersion) {
246 8
                $this->exchangedVersion = true;
247 8
                $this->emit('ready', [$this]);
248 8
                $deferred->resolve($this);
249 3
            }
250 11
        });
251
252 11
        $this->peerAddress = $remotePeer;
253 11
        $this->localVersion = $version = $params->produceVersion($this->msgs, $remotePeer);
254 11
        $this->connectionParams = $params;
255
256 11
        $this->send($version);
257
258 11
        return $deferred->promise();
259
    }
260
261
    /**
262
     *
263
     */
264
    public function intentionalClose()
265
    {
266
        $this->emit('intentionaldisconnect', [$this]);
267
        $this->close();
268
    }
269
270
    /**
271
     *
272
     */
273 8
    public function close()
274
    {
275 8
        $this->emit('close', [$this]);
276 8
        $this->stream->end();
277 8
        $this->removeAllListeners();
278 8
    }
279
280
    /**
281
     * @param int $protocolVersion
282
     * @param int $services
283
     * @param int $timestamp
284
     * @param NetworkAddressInterface $remoteAddr
285
     * @param NetworkAddressInterface $localAddr
286
     * @param string $userAgent
287
     * @param int $blockHeight
288
     * @param bool $relayToUs
289
     */
290
    public function version(
291
        $protocolVersion,
292
        $services,
293
        $timestamp,
294
        NetworkAddressInterface $remoteAddr,
295
        NetworkAddressInterface $localAddr,
296
        $userAgent,
297
        $blockHeight,
298
        $relayToUs
299
    ) {
300
        $this->send($this->msgs->version(
301
            $protocolVersion,
302
            $services,
303
            $timestamp,
304
            $remoteAddr,
305
            $localAddr,
306
            new Buffer($userAgent),
307
            $blockHeight,
308
            $relayToUs
309
        ));
310
    }
311
312
    /**
313
     *
314
     */
315 11
    public function verack()
316
    {
317 11
        $this->send($this->msgs->verack());
318 11
    }
319
320
    /**
321
     *
322
     */
323
    public function sendheaders()
324
    {
325
        $this->send($this->msgs->sendheaders());
326
    }
327
328
    /**
329
     * @param Inventory[] $vInv
330
     */
331
    public function inv(array $vInv)
332
    {
333
        $this->send($this->msgs->inv($vInv));
334
    }
335
336
    /**
337
     * @param Inventory[] $vInv
338
     */
339
    public function getdata(array $vInv)
340
    {
341
        $this->send($this->msgs->getdata($vInv));
342
    }
343
344
    /**
345
     * @param array $vInv
346
     */
347
    public function notfound(array $vInv)
348
    {
349
        $this->send($this->msgs->notfound($vInv));
350
    }
351
352
    /**
353
     * @param NetworkAddressTimestamp[] $vNetAddr
354
     */
355
    public function addr(array $vNetAddr)
356
    {
357
        $this->send($this->msgs->addr($vNetAddr));
358
    }
359
360
    /**
361
     *
362
     */
363
    public function getaddr()
364
    {
365
        $this->send($this->msgs->getaddr());
366
    }
367
368
    /**
369
     *
370
     */
371
    public function ping()
372
    {
373
        $this->send($this->msgs->ping());
374
    }
375
376
    /**
377
     * @param Ping $ping
378
     */
379
    public function pong(Ping $ping)
380
    {
381
        $this->send($this->msgs->pong($ping));
382
    }
383
384
    /**
385
     * @param TransactionInterface $tx
386
     */
387
    public function tx(TransactionInterface $tx)
388
    {
389
        $this->send($this->msgs->tx($tx));
390
    }
391
392
    /**
393
     * @param BlockLocator $locator
394
     */
395
    public function getblocks(BlockLocator $locator)
396
    {
397
        $this->send($this->msgs->getblocks(
398
            $this->localVersion->getVersion(),
399
            $locator
400
        ));
401
    }
402
403
    /**
404
     * @param BlockLocator $locator
405
     */
406
    public function getheaders(BlockLocator $locator)
407
    {
408
        $this->send($this->msgs->getheaders(
409
            $this->localVersion->getVersion(),
410
            $locator
411
        ));
412
    }
413
414
    /**
415
     * @param BlockInterface $block
416
     */
417
    public function block(BlockInterface $block)
418
    {
419
        $this->send($this->msgs->block($block));
420
    }
421
422
    /**
423
     * @param array $vHeaders
424
     */
425
    public function headers(array $vHeaders)
426
    {
427
        $this->send($this->msgs->headers($vHeaders));
428
    }
429
430
    /**
431
     * @param AlertDetail $detail
432
     * @param SignatureInterface $signature
433
     */
434
    public function alert(AlertDetail $detail, SignatureInterface $signature)
435
    {
436
        $this->send($this->msgs->alert($detail, $signature));
437
    }
438
439
    /**
440
     * @param int $feeRate
441
     */
442
    public function feefilter($feeRate)
443
    {
444
        $this->send($this->msgs->feefilter($feeRate));
445
    }
446
447
    /**
448
     * @param BufferInterface $data
449
     */
450
    public function filteradd(BufferInterface $data)
451
    {
452
        $this->send($this->msgs->filteradd($data));
453
    }
454
455
    /**
456
     * @param BloomFilter $filter
457
     */
458
    public function filterload(BloomFilter $filter)
459
    {
460
        $this->send($this->msgs->filterload($filter));
461
    }
462
463
    /**
464
     *
465
     */
466
    public function filterclear()
467
    {
468
        $this->send($this->msgs->filterclear());
469
    }
470
471
    /**
472
     * @param FilteredBlock $filtered
473
     */
474
    public function merkleblock(FilteredBlock $filtered)
475
    {
476
        $this->send($this->msgs->merkleblock($filtered));
477
    }
478
479
    /**
480
     *
481
     */
482
    public function mempool()
483
    {
484
        $this->send($this->msgs->mempool());
485
    }
486
487
    /**
488
     * Issue a Reject message, with a required $msg, $code, and $reason
489
     *
490
     * @param BufferInterface $msg
491
     * @param int $code
492
     * @param BufferInterface $reason
493
     * @param BufferInterface $data
494
     */
495
    public function reject(BufferInterface $msg, $code, BufferInterface $reason, BufferInterface $data = null)
496
    {
497
        $this->send($this->msgs->reject($msg, $code, $reason, $data));
498
    }
499
}
500