Completed
Pull Request — master (#684)
by
unknown
38:06
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 5.2742

Importance

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