Completed
Pull Request — master (#64)
by thomas
56:33 queued 53:42
created

Locator   A

Complexity

Total Complexity 10

Size/Duplication

Total Lines 129
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 5

Test Coverage

Coverage 98.25%

Importance

Changes 12
Bugs 2 Features 3
Metric Value
wmc 10
c 12
b 2
f 3
lcom 1
cbo 5
dl 0
loc 129
ccs 56
cts 57
cp 0.9825
rs 10

5 Methods

Rating   Name   Duplication   Size   Complexity  
A getKnownAddresses() 0 4 1
A __construct() 0 4 1
A dnsSeedHosts() 0 18 2
A queryDnsSeeds() 0 55 4
A popAddress() 0 8 2
1
<?php
2
3
namespace BitWasp\Bitcoin\Networking\Peer;
4
5
use BitWasp\Bitcoin\Networking\Ip\Ipv4;
6
use BitWasp\Bitcoin\Networking\Services;
7
use BitWasp\Bitcoin\Networking\Structure\NetworkAddress;
8
use BitWasp\Bitcoin\Networking\Structure\NetworkAddressInterface;
9
use React\Dns\Resolver\Resolver;
10
use React\Promise\Deferred;
11
12
class Locator
13
{
14
15
    /**
16
     * @var Resolver
17
     */
18
    private $dns;
19
20
    /**
21
     * @var NetworkAddressInterface[]
22
     */
23
    private $knownAddresses = [];
24
25
    /**
26
     * @param Resolver $dns
27
     */
28 6
    public function __construct(Resolver $dns)
29
    {
30 6
        $this->dns = $dns;
31 6
    }
32
33
    /**
34
     * @param bool $randomize - return a randomized list of dns seeds
35
     * @return string[]
36
     */
37 6
    public static function dnsSeedHosts($randomize = true)
38
    {
39
        $seeds = [
40 6
            'seed.bitcoin.sipa.be',
41 4
            'dnsseed.bluematt.me',
42 4
            'dnsseed.bitcoin.dashjr.org',
43 4
            'seed.bitcoinstats.com',
44 4
            'bitseed.xf2.org',
45 4
            'seed.bitnodes.io',
46
            "seed.bitcoin.jonasschnelli.ch"
47 4
        ];
48
49 6
        if ($randomize) {
50 6
            shuffle($seeds);
51 4
        }
52
53 6
        return $seeds;
54
    }
55
56
    /**
57
     * Connect to $numSeeds DNS seeds
58
     *
59
     * @param int $numSeeds
60
     * @return \React\Promise\Promise|\React\Promise\PromiseInterface
61
     */
62 3
    public function queryDnsSeeds($numSeeds = 1)
63
    {
64 3
        $peerList = new Deferred();
65
66
        // Take $numSeeds
67 3
        $seedHosts = self::dnsSeedHosts();
68 3
        $seeds = array_slice($seedHosts, 0, min($numSeeds, count($seedHosts)));
69
70
        // Connect to $numSeeds peers
71
        /** @var Peer[] $vNetAddr */
72 3
        $vNetAddr = [];
73 3
        foreach ($seeds as $seed) {
74 3
            $this->dns
75 3
                ->resolve($seed)
76
                ->then(function ($ipList) use (&$vNetAddr, $peerList, &$numSeeds) {
77 3
                    $vNetAddr[] = $ipList;
78 3
                    if (count($vNetAddr) == $numSeeds) {
79 3
                        $peerList->resolve($vNetAddr);
80 2
                    }
81 3
                })
82
            ;
83 2
        }
84
85
        // Compile the list of lists of peers into $this->knownAddresses
86
        return $peerList
87 3
            ->promise()
88 3
            ->then(
89
                function (array $vPeerVAddrs) {
90 3
                    shuffle($vPeerVAddrs);
91
92
                    /** @var NetworkAddressInterface[] $addresses */
93 3
                    $addresses = [];
94 3
                    array_map(
95 3
                        function (array $value) use (&$addresses) {
96 3
                            foreach ($value as $ip) {
97 3
                                $addresses[] = new NetworkAddress(
98 3
                                    Services::NETWORK,
99 3
                                    new Ipv4($ip),
100 1
                                    8333
101 2
                                );
102 2
                            }
103 3
                        },
104
                        $vPeerVAddrs
105 2
                    );
106
107 3
                    $this->knownAddresses = array_merge(
108 3
                        $this->knownAddresses,
109
                        $addresses
110 2
                    );
111
                    
112 3
                    return $this;
113 1
                }
114 2
            )
115 2
        ;
116
    }
117
118
    /**
119
     * @return NetworkAddressInterface[]
120
     */
121 3
    public function getKnownAddresses()
122
    {
123 3
        return $this->knownAddresses;
124
    }
125
126
    /**
127
     * Pop an address from the discovered peers
128
     *
129
     * @return NetworkAddressInterface
130
     * @throws \Exception
131
     */
132 3
    public function popAddress()
133
    {
134 3
        if (count($this->knownAddresses) < 1) {
135 3
            throw new \Exception('No peers');
136
        }
137
138
        return array_pop($this->knownAddresses);
139
    }
140
}
141