Completed
Push — master ( 226900...81ddff )
by thomas
18:25
created

Network::validateHexStringRepresentsBytes()   B

Complexity

Conditions 5
Paths 5

Size

Total Lines 20
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 6.2017

Importance

Changes 0
Metric Value
cc 5
eloc 10
nc 5
nop 2
dl 0
loc 20
ccs 7
cts 11
cp 0.6364
crap 6.2017
rs 8.8571
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace BitWasp\Bitcoin\Network;
6
7
use BitWasp\Bitcoin\Exceptions\InvalidNetworkParameter;
8
use BitWasp\Bitcoin\Exceptions\MissingBase58Prefix;
9
use BitWasp\Bitcoin\Exceptions\MissingBech32Prefix;
10
use BitWasp\Bitcoin\Exceptions\MissingBip32Prefix;
11
use BitWasp\Bitcoin\Exceptions\MissingNetworkParameter;
12
13
class Network implements NetworkInterface
14
{
15
    const BECH32_PREFIX_SEGWIT = "segwit";
16
17
    const BASE58_ADDRESS_P2PKH = "p2pkh";
18
    const BASE58_ADDRESS_P2SH = "p2sh";
19
    const BASE58_WIF = "wif";
20
    const BIP32_PREFIX_XPUB = "xpub";
21
    const BIP32_PREFIX_XPRV = "xprv";
22
23
    /**
24
     * @var array map of base58 address type to byte
25
     */
26
    protected $base58PrefixMap = [];
27
28
    /**
29
     * @var array map of bech32 address type to HRP
30
     */
31
    protected $bech32PrefixMap = [];
32
33
    /**
34
     * @var array map of bip32 type to bytes
35
     */
36
    protected $bip32PrefixMap = [];
37
38
    /**
39
     * @var array map of bip32 key type to script type
40
     */
41
    protected $bip32ScriptTypeMap = [];
42
43
    /**
44
     * @var string - message prefix for bitcoin signed messages
45
     */
46
    protected $signedMessagePrefix;
47
48
    /**
49
     * @var string - 4 bytes for p2p magic
50
     */
51
    protected $p2pMagic;
52
53
    /**
54
     * @param string $field - name of field being validated
55
     * @param string $value - we check this value
56
     * @param int $length - length we require
0 ignored issues
show
Bug introduced by
There is no parameter named $length. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
57
     * @throws InvalidNetworkParameter
58
     */
59 142
    private function validateHexStringRepresentsBytes(string $field, string $value)
60
    {
61 142
        if (!is_string($value)) {
62
            throw new InvalidNetworkParameter("{$field} must be a string");
63
        }
64
65 142
        $length = strlen($value);
66
67 142
        if ($length == 0) {
68
            throw new InvalidNetworkParameter("{$field} must be non-empty string");
69
        }
70
71 142
        if ($length % 2 !== 0) {
72
            throw new InvalidNetworkParameter("{$field} must have even number of characters (hex representing bytes)");
73
        }
74
75 142
        if (!ctype_xdigit($value)) {
76
            throw new InvalidNetworkParameter("{$field} prefix must be a valid hex string");
77
        }
78 142
    }
79
80
    /**
81
     * Network constructor.
82
     * @throws InvalidNetworkParameter
83
     */
84 142
    public function __construct()
85
    {
86 142
        if (null !== $this->p2pMagic) {
87 142
            $this->validateHexStringRepresentsBytes("P2P magic", $this->p2pMagic);
88
        }
89
90 142
        foreach ($this->base58PrefixMap as $type => $byte) {
91 142
            $this->validateHexStringRepresentsBytes("{$type} base58 prefix", $byte);
92
        }
93
94 142
        foreach ($this->bip32PrefixMap as $type => $bytes) {
95 142
            $this->validateHexStringRepresentsBytes("{$type} bip32 prefix", $bytes);
96
        }
97
98 142
        if (count($this->bip32ScriptTypeMap) !== count($this->bip32PrefixMap)) {
99
            throw new InvalidNetworkParameter("BIP32 prefixes not configured correctly. Number of items does not match.");
100
        }
101 142
    }
102
103
    /**
104
     * @param string $prefixType
105
     * @return bool
106
     */
107 80
    protected function hasBase58Prefix(string $prefixType): bool
108
    {
109 80
        return array_key_exists($prefixType, $this->base58PrefixMap);
110
    }
111
112
    /**
113
     * @param string $prefixType
114
     * @return string
115
     * @throws MissingBase58Prefix
116
     */
117 78
    protected function getBase58Prefix(string $prefixType): string
118
    {
119 78
        if (!$this->hasBase58Prefix($prefixType)) {
120 1
            throw new MissingBase58Prefix();
121
        }
122 77
        return $this->base58PrefixMap[$prefixType];
123
    }
124
125
    /**
126
     * @param string $prefixType
127
     * @return bool
128
     */
129 42
    protected function hasBech32Prefix(string $prefixType): bool
130
    {
131 42
        return array_key_exists($prefixType, $this->bech32PrefixMap);
132
    }
133
134
    /**
135
     * @param string $prefixType
136
     * @return string
137
     * @throws MissingBech32Prefix
138
     */
139 40
    protected function getBech32Prefix(string $prefixType): string
140
    {
141 40
        if (!$this->hasBech32Prefix($prefixType)) {
142 1
            throw new MissingBech32Prefix();
143
        }
144 39
        return $this->bech32PrefixMap[$prefixType];
145
    }
146
147
    /**
148
     * @param string $prefixType
149
     * @return bool
150
     */
151 65
    protected function hasBip32Prefix(string $prefixType): bool
152
    {
153 65
        return array_key_exists($prefixType, $this->bip32PrefixMap);
154
    }
155
156
    /**
157
     * @param string $prefixType
158
     * @return string
159
     * @throws MissingBip32Prefix
160
     */
161 63
    protected function getBip32Prefix(string $prefixType): string
162
    {
163 63
        if (!$this->hasBip32Prefix($prefixType)) {
164 1
            throw new MissingBip32Prefix();
165
        }
166 62
        return $this->bip32PrefixMap[$prefixType];
167
    }
168
169
    /**
170
     * @return string
171
     * @throws MissingNetworkParameter
172
     * @see NetworkInterface::getSignedMessageMagic
173
     */
174 22
    public function getSignedMessageMagic(): string
175
    {
176 22
        if (null === $this->signedMessagePrefix) {
177
            throw new MissingNetworkParameter("Missing magic string for signed message");
178
        }
179 22
        return $this->signedMessagePrefix;
180
    }
181
182
    /**
183
     * @return string
184
     * @throws MissingNetworkParameter
185
     * @see NetworkInterface::getNetMagicBytes()
186
     */
187 15
    public function getNetMagicBytes(): string
188
    {
189 15
        if (null === $this->p2pMagic) {
190
            throw new MissingNetworkParameter("Missing network magic bytes");
191
        }
192 15
        return $this->p2pMagic;
193
    }
194
195
    /**
196
     * @return string
197
     * @throws MissingBase58Prefix
198
     */
199 28
    public function getPrivByte(): string
200
    {
201 28
        return $this->getBase58Prefix(self::BASE58_WIF);
202
    }
203
204
    /**
205
     * @return string
206
     * @throws MissingBase58Prefix
207
     * @see NetworkInterface::getAddressByte()
208
     */
209 48
    public function getAddressByte(): string
210
    {
211 48
        return $this->getBase58Prefix(self::BASE58_ADDRESS_P2PKH);
212
    }
213
    /**
214
     * @return int
215
     * @throws MissingBase58Prefix
216
     * @see NetworkInterface::getAddressPrefixLength()
217
     */
218 22
    public function getAddressPrefixLength(): int
219
    {
220 22
        return strlen($this->getAddressByte()) / 2;
221
    }
222
223
    /**
224
     * @return string
225
     * @throws MissingBase58Prefix
226
     * @see NetworkInterface::getP2shByte()
227
     */
228 55
    public function getP2shByte(): string
229
    {
230 55
        return $this->getBase58Prefix(self::BASE58_ADDRESS_P2SH);
231
    }
232
233
    /**
234
     * @return int
235
     * @throws MissingBase58Prefix
236
     * @see NetworkInterface::getP2shPrefixLength()
237
     */
238 33
    public function getP2shPrefixLength(): int
239
    {
240 33
        return strlen($this->getP2shByte()) / 2;
241
    }
242
243
    /**
244
     * @return string
245
     * @throws MissingBip32Prefix
246
     * @see NetworkInterface::getHDPubByte()
247
     */
248 61
    public function getHDPubByte(): string
249
    {
250 61
        return $this->getBip32Prefix(self::BIP32_PREFIX_XPUB);
251
    }
252
253
    /**
254
     * @return string
255
     * @throws MissingBip32Prefix
256
     * @see NetworkInterface::getHDPrivByte()
257
     */
258 61
    public function getHDPrivByte(): string
259
    {
260 61
        return $this->getBip32Prefix(self::BIP32_PREFIX_XPRV);
261
    }
262
263
    /**
264
     * @return string
265
     * @throws MissingBech32Prefix
266
     * @see NetworkInterface::getSegwitBech32Prefix()
267
     */
268 38
    public function getSegwitBech32Prefix(): string
269
    {
270 38
        return $this->getBech32Prefix(self::BECH32_PREFIX_SEGWIT);
271
    }
272
}
273