Completed
Push — 0.0.35 ( b2fc74...d8d049 )
by thomas
28:12 queued 09:10
created

Network   A

Complexity

Total Complexity 28

Size/Duplication

Total Lines 229
Duplicated Lines 0 %

Coupling/Cohesion

Components 5
Dependencies 5

Test Coverage

Coverage 90.74%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
dl 0
loc 229
ccs 49
cts 54
cp 0.9074
rs 10
c 1
b 0
f 0
wmc 28
lcom 5
cbo 5

16 Methods

Rating   Name   Duplication   Size   Complexity  
A validateHexString() 0 10 4
B __construct() 0 18 5
A hasBase58Prefix() 0 4 1
A getBase58Prefix() 0 7 2
A hasBech32Prefix() 0 4 1
A getBech32Prefix() 0 7 2
A hasBip32Prefix() 0 4 1
A getBip32Prefix() 0 7 2
A getSignedMessageMagic() 0 7 2
A getNetMagicBytes() 0 7 2
A getPrivByte() 0 4 1
A getAddressByte() 0 4 1
A getP2shByte() 0 4 1
A getHDPubByte() 0 4 1
A getHDPrivByte() 0 4 1
A getSegwitBech32Prefix() 0 4 1
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
     */
56 109
    private function validateHexString($field, $value, $length)
57
    {
58 109
        if (!is_string($value) || strlen($value) !== 2 * $length) {
59
            throw new InvalidNetworkParameter("{$field} must be a {$length} byte hex string");
60
        }
61
62 109
        if (!ctype_xdigit($value)) {
63
            throw new InvalidNetworkParameter("{$field} prefix must be a valid hex string");
64
        }
65 109
    }
66
67
    /**
68
     * Network constructor.
69
     */
70 109
    public function __construct()
71
    {
72 109
        if (null !== $this->p2pMagic) {
73 109
            $this->validateHexString("P2P magic", $this->p2pMagic, 4);
74
        }
75
76 109
        foreach ($this->base58PrefixMap as $type => $byte) {
77 109
            $this->validateHexString("{$type} base58 prefix", $byte, 1);
78
        }
79
80 109
        foreach ($this->bip32PrefixMap as $type => $bytes) {
81 109
            $this->validateHexString("{$type} bip32 prefix", $bytes, 4);
82
        }
83
84 109
        if (count($this->bip32ScriptTypeMap) !== count($this->bip32PrefixMap)) {
85
            throw new InvalidNetworkParameter("BIP32 prefixes not configured correctly");
86
        }
87 109
    }
88
89
    /**
90
     * @param string $prefixType
91
     * @return bool
92
     */
93 61
    protected function hasBase58Prefix($prefixType)
94
    {
95 61
        return array_key_exists($prefixType, $this->base58PrefixMap);
96
    }
97
98
    /**
99
     * @param string $prefixType
100
     * @return string
101
     * @throws MissingBase58Prefix
102
     */
103 59
    protected function getBase58Prefix($prefixType)
104
    {
105 59
        if (!$this->hasBase58Prefix($prefixType)) {
106 1
            throw new MissingBase58Prefix();
107
        }
108 58
        return $this->base58PrefixMap[$prefixType];
109
    }
110
111
    /**
112
     * @param string $prefixType
113
     * @return bool
114
     */
115 36
    protected function hasBech32Prefix($prefixType)
116
    {
117 36
        return array_key_exists($prefixType, $this->bech32PrefixMap);
118
    }
119
120
    /**
121
     * @param string $prefixType
122
     * @return string
123
     * @throws MissingBech32Prefix
124
     */
125 34
    protected function getBech32Prefix($prefixType)
126
    {
127 34
        if (!$this->hasBech32Prefix($prefixType)) {
128 1
            throw new MissingBech32Prefix();
129
        }
130 33
        return $this->bech32PrefixMap[$prefixType];
131
    }
132
133
    /**
134
     * @param string $prefixType
135
     * @return bool
136
     */
137 59
    protected function hasBip32Prefix($prefixType)
138
    {
139 59
        return array_key_exists($prefixType, $this->bip32PrefixMap);
140
    }
141
142
    /**
143
     * @param $prefixType
144
     * @return mixed
145
     * @throws MissingBip32Prefix
146
     */
147 57
    protected function getBip32Prefix($prefixType)
148
    {
149 57
        if (!$this->hasBip32Prefix($prefixType)) {
150 1
            throw new MissingBip32Prefix();
151
        }
152 56
        return $this->bip32PrefixMap[$prefixType];
153
    }
154
155
    /**
156
     * @return string
157
     * @throws MissingNetworkParameter
158
     * @see NetworkInterface::getSignedMessageMagic
159
     */
160 21
    public function getSignedMessageMagic()
161
    {
162 21
        if (null === $this->signedMessagePrefix) {
163
            throw new MissingNetworkParameter("Missing magic string for signed message");
164
        }
165 21
        return $this->signedMessagePrefix;
166
    }
167
168
    /**
169
     * @return string
170
     * @throws MissingNetworkParameter
171
     * @see NetworkInterface::getNetMagicBytes()
172
     */
173 15
    public function getNetMagicBytes()
174
    {
175 15
        if (null === $this->p2pMagic) {
176
            throw new MissingNetworkParameter("Missing network magic bytes");
177
        }
178 15
        return $this->p2pMagic;
179
    }
180
181
    /**
182
     * @return string
183
     * @throws MissingBase58Prefix
184
     */
185 21
    public function getPrivByte()
186
    {
187 21
        return $this->getBase58Prefix(self::BASE58_WIF);
188
    }
189
190
    /**
191
     * @return string
192
     * @throws MissingBase58Prefix
193
     * @see NetworkInterface::getAddressByte()
194
     */
195 39
    public function getAddressByte()
196
    {
197 39
        return $this->getBase58Prefix(self::BASE58_ADDRESS_P2PKH);
198
    }
199
200
    /**
201
     * @return string
202
     * @throws MissingBase58Prefix
203
     * @see NetworkInterface::getP2shByte()
204
     */
205 45
    public function getP2shByte()
206
    {
207 45
        return $this->getBase58Prefix(self::BASE58_ADDRESS_P2SH);
208
    }
209
210
    /**
211
     * @return mixed|string
212
     * @throws MissingBip32Prefix
213
     * @see NetworkInterface::getHDPubByte()
214
     */
215 55
    public function getHDPubByte()
216
    {
217 55
        return $this->getBip32Prefix(self::BIP32_PREFIX_XPUB);
218
    }
219
220
    /**
221
     * @return mixed|string
222
     * @throws MissingBip32Prefix
223
     * @see NetworkInterface::getHDPrivByte()
224
     */
225 55
    public function getHDPrivByte()
226
    {
227 55
        return $this->getBip32Prefix(self::BIP32_PREFIX_XPRV);
228
    }
229
230
    /**
231
     * @return string
232
     * @throws MissingBech32Prefix
233
     * @see NetworkInterface::getSegwitBech32Prefix()
234
     */
235 32
    public function getSegwitBech32Prefix()
236
    {
237 32
        return $this->getBech32Prefix(self::BECH32_PREFIX_SEGWIT);
238
    }
239
}
240