Completed
Pull Request — master (#583)
by thomas
58:28 queued 55:50
created

Network::getBase58Prefix()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 4
nc 2
nop 1
dl 0
loc 7
ccs 4
cts 4
cp 1
crap 2
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
namespace BitWasp\Bitcoin\Network;
4
5
use BitWasp\Bitcoin\Exceptions\InvalidNetworkParameter;
6
use BitWasp\Bitcoin\Exceptions\MissingBase58Prefix;
7
use BitWasp\Bitcoin\Exceptions\MissingBech32Prefix;
8
use BitWasp\Bitcoin\Exceptions\MissingBip32Prefix;
9
use BitWasp\Bitcoin\Exceptions\MissingNetworkParameter;
10
11
class Network implements NetworkInterface
12
{
13
    const BECH32_PREFIX_SEGWIT = "segwit";
14
15
    const BASE58_ADDRESS_P2PKH = "p2pkh";
16
    const BASE58_ADDRESS_P2SH = "p2sh";
17
    const BASE58_WIF = "wif";
18
    const BIP32_PREFIX_XPUB = "xpub";
19
    const BIP32_PREFIX_XPRV = "xprv";
20
21
    /**
22
     * @var array map of base58 address type to byte
23
     */
24
    protected $base58PrefixMap = [];
25
26
    /**
27
     * @var array map of bech32 address type to HRP
28
     */
29
    protected $bech32PrefixMap = [];
30
31
    /**
32
     * @var array map of bip32 type to bytes
33
     */
34
    protected $bip32PrefixMap = [];
35
36
    /**
37
     * @var array map of bip32 key type to script type
38
     */
39
    protected $bip32ScriptTypeMap = [];
40
41
    /**
42
     * @var string - message prefix for bitcoin signed messages
43
     */
44
    protected $signedMessagePrefix;
45
46
    /**
47
     * @var string - 4 bytes for p2p magic
48
     */
49
    protected $p2pMagic;
50
51
    /**
52
     * @param string $field - name of field being validated
53
     * @param mixed $value - we check this value
54
     * @param int $length - length we require
55
     * @throws InvalidNetworkParameter
56
     */
57 89
    private function validateHexString($field, $value, $length)
58
    {
59 89
        if (!is_string($value) || strlen($value) !== 2 * $length) {
60
            throw new InvalidNetworkParameter("{$field} must be a {$length} byte hex string");
61
        }
62
63 89
        if (!ctype_xdigit($value)) {
64
            throw new InvalidNetworkParameter("{$field} prefix must be a valid hex string");
65
        }
66 89
    }
67
68
    /**
69
     * Network constructor.
70
     * @throws InvalidNetworkParameter
71
     */
72 89
    public function __construct()
73
    {
74 89
        if (null !== $this->p2pMagic) {
75 89
            $this->validateHexString("P2P magic", $this->p2pMagic, 4);
76
        }
77
78 89
        foreach ($this->base58PrefixMap as $type => $byte) {
79 89
            $this->validateHexString("{$type} base58 prefix", $byte, 1);
80
        }
81
82 89
        foreach ($this->bip32PrefixMap as $type => $bytes) {
83 89
            $this->validateHexString("{$type} bip32 prefix", $bytes, 4);
84
        }
85
86 89
        if (count($this->bip32ScriptTypeMap) !== count($this->bip32PrefixMap)) {
87
            throw new InvalidNetworkParameter("BIP32 prefixes not configured correctly");
88
        }
89 89
    }
90
91
    /**
92
     * @param string $prefixType
93
     * @return bool
94
     */
95 58
    protected function hasBase58Prefix($prefixType)
96
    {
97 58
        return array_key_exists($prefixType, $this->base58PrefixMap);
98
    }
99
100
    /**
101
     * @param string $prefixType
102
     * @return string
103
     * @throws MissingBase58Prefix
104
     */
105 56
    protected function getBase58Prefix($prefixType)
106
    {
107 56
        if (!$this->hasBase58Prefix($prefixType)) {
108 1
            throw new MissingBase58Prefix();
109
        }
110 55
        return $this->base58PrefixMap[$prefixType];
111
    }
112
113
    /**
114
     * @param string $prefixType
115
     * @return bool
116
     */
117 35
    protected function hasBech32Prefix($prefixType)
118
    {
119 35
        return array_key_exists($prefixType, $this->bech32PrefixMap);
120
    }
121
122
    /**
123
     * @param string $prefixType
124
     * @return string
125
     * @throws MissingBech32Prefix
126
     */
127 33
    protected function getBech32Prefix($prefixType)
128
    {
129 33
        if (!$this->hasBech32Prefix($prefixType)) {
130 1
            throw new MissingBech32Prefix();
131
        }
132 32
        return $this->bech32PrefixMap[$prefixType];
133
    }
134
135
    /**
136
     * @param string $prefixType
137
     * @return bool
138
     */
139 42
    protected function hasBip32Prefix($prefixType)
140
    {
141 42
        return array_key_exists($prefixType, $this->bip32PrefixMap);
142
    }
143
144
    /**
145
     * @param $prefixType
146
     * @return mixed
147
     * @throws MissingBip32Prefix
148
     */
149 40
    protected function getBip32Prefix($prefixType)
150
    {
151 40
        if (!$this->hasBip32Prefix($prefixType)) {
152 1
            throw new MissingBip32Prefix();
153
        }
154 39
        return $this->bip32PrefixMap[$prefixType];
155
    }
156
157
    /**
158
     * @return string
159
     * @throws MissingNetworkParameter
160
     * @see NetworkInterface::getSignedMessageMagic
161
     */
162 11
    public function getSignedMessageMagic()
163
    {
164 11
        if (null === $this->signedMessagePrefix) {
165
            throw new MissingNetworkParameter("Missing magic string for signed message");
166
        }
167 11
        return $this->signedMessagePrefix;
168
    }
169
170
    /**
171
     * @return string
172
     * @throws MissingNetworkParameter
173
     * @see NetworkInterface::getNetMagicBytes()
174
     */
175 15
    public function getNetMagicBytes()
176
    {
177 15
        if (null === $this->p2pMagic) {
178
            throw new MissingNetworkParameter("Missing network magic bytes");
179
        }
180 15
        return $this->p2pMagic;
181
    }
182
183
    /**
184
     * @return string
185
     * @throws MissingBase58Prefix
186
     */
187 19
    public function getPrivByte()
188
    {
189 19
        return $this->getBase58Prefix(self::BASE58_WIF);
190
    }
191
192
    /**
193
     * @return string
194
     * @throws MissingBase58Prefix
195
     * @see NetworkInterface::getAddressByte()
196
     */
197 36
    public function getAddressByte()
198
    {
199 36
        return $this->getBase58Prefix(self::BASE58_ADDRESS_P2PKH);
200
    }
201
202
    /**
203
     * @return string
204
     * @throws MissingBase58Prefix
205
     * @see NetworkInterface::getP2shByte()
206
     */
207 47
    public function getP2shByte()
208
    {
209 47
        return $this->getBase58Prefix(self::BASE58_ADDRESS_P2SH);
210
    }
211
212
    /**
213
     * @return mixed|string
214
     * @throws MissingBip32Prefix
215
     * @see NetworkInterface::getHDPubByte()
216
     */
217 38
    public function getHDPubByte()
218
    {
219 38
        return $this->getBip32Prefix(self::BIP32_PREFIX_XPUB);
220
    }
221
222
    /**
223
     * @return mixed|string
224
     * @throws MissingBip32Prefix
225
     * @see NetworkInterface::getHDPrivByte()
226
     */
227 38
    public function getHDPrivByte()
228
    {
229 38
        return $this->getBip32Prefix(self::BIP32_PREFIX_XPRV);
230
    }
231
232
    /**
233
     * @return string
234
     * @throws MissingBech32Prefix
235
     * @see NetworkInterface::getSegwitBech32Prefix()
236
     */
237 31
    public function getSegwitBech32Prefix()
238
    {
239 31
        return $this->getBech32Prefix(self::BECH32_PREFIX_SEGWIT);
240
    }
241
}
242